小例子 服务器端用libevent 处理监听多个端口, 客户端多线程数据发送过来的时候写入对应不同文件中。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_CONNECT_NUM 100 //暂定最大的连接数目
#define Port_Begin 10000 //侦听端口的其实端口号
#define DEF_TIME_OUT 20 //暂定超时调用时间设置20s
#define ONCE_READ_LEN 1000 //一次读取套接字的长度
//该结构体,本来想是构建传递给回调函数的
//但最终未用到,以后扩展可用
struct my_struct
{
struct event_base* base;
struct event *ev;
int listener_fd[MAX_CONNECT_NUM];
int connect_fd;
int port_num;
int index;
};
void accept_cb(int fd, short events, void* arg);
void socket_read_cb(int fd, short events, void *arg);
int tcp_server_init(int port, int listen_num);
//定义个全局变量用来记录每一个端口发送过来的数据长度
//由于公用回调函数,无法合适处理计数,借助粗犷的全局变量
int len_from_on_port[MAX_CONNECT_NUM];
int main(int argc, char** argv)
{
struct event evtimeout;
int i,listener[MAX_CONNECT_NUM];
struct event_base* base = event_base_new();
struct event* ev_listen[MAX_CONNECT_NUM];
struct my_struct tran_struct;
tran_struct.base = base;
//再次循环建立多个监听端口,然后设置回调accept函数
for(i=0; i
g++ -o s server_100port.c -I ./include/ -Wl,-Bstatic -L ./lib -levent -Wl,-Bdynamic -lm -lrt
客户端代码则是,利用多线程的方式,去连接服务器的端口,然后读同一个文件,发送,直到发送完毕:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define CONNECT_CLIENT_NUM 100
#define FILE_NAME "update.bin"
#define ONCE_WRITE_LEN 1000
int tcp_connect_server(const char* server_ip, int port);
void * client_connect_thread_function(void * arg);
int main(int argc, char** argv)
{
int i, client_socket_fd[CONNECT_CLIENT_NUM]={0};
pthread_t client_thread[CONNECT_CLIENT_NUM] ;
int begin_port = atoi( argv[2] );
if( argc < 3 )
{
printf("please input like: ./a.out 192.168.1.1 10000 \n");
return -1;
}
i=0;
//如果将for注释掉就为一个线程的情况
for ( i = 0; i < CONNECT_CLIENT_NUM; i++)
{
client_socket_fd[i] = tcp_connect_server(argv[1], begin_port + i);
printf("port:%d,socket_fd:%d; ",begin_port + i,client_socket_fd[i]);
//以下建立分离线程,传入了套接字描述符
pthread_attr_t attr_client;
pthread_attr_init(&attr_client);
pthread_attr_setdetachstate(&attr_client, PTHREAD_CREATE_DETACHED);
pthread_create(&client_thread[i], &attr_client, &client_connect_thread_function,(void *)(&client_socket_fd[i]));
pthread_attr_destroy(&attr_client);
}
//这里暂时用如此粗犷的方法不退出主线程
//暂时未找到合适的等待所有线程结束的函数
while(1)
;
printf("\n\nMain exit\n");
}
void * client_connect_thread_function(void * arg)
{
FILE * stream_out = NULL; //读取文件流
int write_len_count = 0, once_write_len = 0 , i, my_port_num;
int * my_thread_write_fd ;
char buf[ONCE_WRITE_LEN] = {0};
my_thread_write_fd = (int*)arg; //获取传入的参数 为描述符
//以下 获取到服务端的连接的端口,
struct sockaddr_in me;
bzero(&me , sizeof(me));
socklen_t socklen_len = sizeof(me);
if(getpeername(*my_thread_write_fd , (struct sockaddr *)&me , &socklen_len) == 0)
{
my_port_num = ntohs(me. sin_port );
}
//获取当前线程号,和对应连接的服务器端口
printf("I'm thread %lu, server port%d", (unsigned long)pthread_self(), my_port_num);
if((stream_out = fopen (FILE_NAME,"r+"))==NULL)
{
printf("file open error\n");
//exit(1);
}
//一直读文件,然后写入套接字
while( (i = fread(buf, sizeof(char), ONCE_WRITE_LEN, stream_out)) >0)
{
//由于采用阻塞式,没有发送完会组塞到这里
if( (once_write_len=send(*my_thread_write_fd, buf, i, 0)) != i )
{
printf("read %d, while send %d\n",i, once_write_len);
perror("first error");
printf("already send %d \n", write_len_count);
sleep(5);
}
//printf("send %d, ",i);
write_len_count = write_len_count + once_write_len;
once_write_len=0;
}
perror("read file"); //看最终的状态,如果一切正常那么会输出read file: Success
fclose(stream_out);
printf( " %lu thread over, port: %d,write length:%d\n", (unsigned long)pthread_self(), my_port_num, write_len_count);
return NULL;
}
int tcp_connect_server(const char* server_ip, int port)
{
int sockfd, status, save_errno;
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr) );
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
status = inet_aton(server_ip, &server_addr.sin_addr);
if( status == 0 ) //the server_ip is not valid value
{
errno = EINVAL;
return -1;
}
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if( sockfd == -1 )
return sockfd;
status = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr) );
if( status == -1 )
{
perror("connect error");
save_errno = errno;
close(sockfd);
errno = save_errno; //the close may be error
return -1;
}
return sockfd;
}
编译: gcc -o thread_c client_thread.c -lpthread
依次运行服务器程序 ./s
客户端 ./thread_c 192.168.3.90 10000
测试可以
以上,这几天一个新任务是对公司某型号机器进行升级的项目,由于该型机器组网连接,并且已经具有通过网页接受升级文件的功能。
所以该项目就是模拟网页发送文件的方式,然后批量升级机器。
前期通过抓包工具 fiddler,查看浏览器实现升级文件发送的过程,网上辛苦找了个C++下http,post大文件的例子,和同事总算是“拼凑”成了数据,可以用软件对一个机器进行升级文件发送。
然后就是批量升级的模拟,由于公司内网没法模拟用户批量的机器,所以负责人让编写一个模拟程序,通过一个IP,多个端口的方式,来模拟多个机器文件接收。
当然程序还有待改进, 由于采用粗犷的编程方式,CPU占用飙升是肯定的。
所以有了上述服务器端的例子,为了测试服务器端的例子,自己有编写了上边客户端例子,记录下来,忘的太快了。