文章标题
来源:互联网 发布:vb书籍 编辑:程序博客网 时间:2024/05/19 19:32
利用libevent和多线程 实现多并发的服务器的设计。主进程监听连接的到来使用一个base,进行事件循环。每当 一个连接进来时,创建一个新的线程实现与客户端之间的通信,子线程建立一个base,进行事件循环
客户端(多线程):
主线程->连接描述符(socket_fd = connectServer(ip, port);)
-》创建子进程(init_read_event_thread(socket_fd);)
-》 pthread_create(&thread,NULL,init_read_event,(void*)sock);
-》创建base,并且建立事件循环(
void* init_read_event(void* arg)
->事件的回调函数
-》写数据给服务端
服务器(多线程)(base): ( 主要是一个线程一个base)
主线程-》listen(fd, 10);
-》设置事件循环
event_set(&listen_ev, fd, EV_READ|EV_PERSIST, on_accept, NULL);(等待连接的到来) -》得到连接描述符子线程 (base): accept_new_thread(new_fd); pthread_create(&thread,NULL,process_in_new_thread_when_accepted,(void*)sock); -》process_in_new_thread_when_accepted(void* arg) ->设置事件循环
服务器端程序:
#include <iostream>#include <sys/select.h>#include <sys/socket.h>#include <stdio.h>#include <unistd.h>#include <pthread.h>#include <stdio.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string>#include <string.h>#include <event.h>#include <stdlib.h>using namespace std;#define SERVER_IP "127.0.0.1"#define SERVER_PORT 9090#define BUF_SIZE 1024struct sock_ev_write{//用户写事件完成后的销毁,在on_write()中执行 struct event* write_ev; char* buffer;};struct sock_ev {//用于读事件终止(socket断开)后的销毁 struct event_base* base;//因为socket断掉后,读事件的loop要终止,所以要有base指针 struct event* read_ev;};/** * 销毁写事件用到的结构体 */void destroy_sock_ev_write(struct sock_ev_write* sock_ev_write_struct){ if(NULL != sock_ev_write_struct){// event_del(sock_ev_write_struct->write_ev);//因为写事件没用EV_PERSIST,故不用event_del if(NULL != sock_ev_write_struct->write_ev){ free(sock_ev_write_struct->write_ev); } if(NULL != sock_ev_write_struct->buffer){ delete[]sock_ev_write_struct->buffer; } free(sock_ev_write_struct); }}/** * 读事件结束后,用于销毁相应的资源 */void destroy_sock_ev(struct sock_ev* sock_ev_struct){ if(NULL == sock_ev_struct){ return; } event_del(sock_ev_struct->read_ev); event_base_loopexit(sock_ev_struct->base, NULL);//停止loop循环 if(NULL != sock_ev_struct->read_ev){ free(sock_ev_struct->read_ev); cout<<"free read_ev succeed"<<endl; }/* if(NULL !=sock_ev_struct->base) { event_base_free(sock_ev_struct->base); cout<<"free base succeed"<<endl; }*/// destroy_sock_ev_write(sock_ev_struct->sock_ev_write_struct); if(NULL !=sock_ev_struct) { free(sock_ev_struct); cout<<"free sock_ev_struct"<<endl; }}int getSocket(){ int fd =socket( AF_INET, SOCK_STREAM, 0 ); if(-1 == fd){ cout<<"Error, fd is -1"<<endl; } return fd;}void on_write(int sock, short event, void* arg){ cout<<"on_write() called, sock="<<sock<<endl; if(NULL == arg){ cout<<"Error! void* arg is NULL in on_write()"<<endl; return; } struct sock_ev_write* sock_ev_write_struct = (struct sock_ev_write*)arg; char buffer[BUF_SIZE]; sprintf(buffer, "fd=%d, received[%s]", sock, sock_ev_write_struct->buffer);// int write_num0 = write(sock, sock_ev_write_struct->buffer, strlen(sock_ev_write_struct->buffer));// int write_num = write(sock, sock_ev_write_struct->buffer, strlen(sock_ev_write_struct->buffer)); int write_num = write(sock, buffer, strlen(buffer)); destroy_sock_ev_write(sock_ev_write_struct); cout<<"on_write() finished, sock="<<sock<<endl;}void on_read(int sock, short event, void* arg){ cout<<"on_read() called, sock="<<sock<<endl; if(NULL == arg){ return; } struct sock_ev* event_struct = (struct sock_ev*) arg;//获取传进来的参数 char* buffer = new char[BUF_SIZE]; memset(buffer, 0, sizeof(char)*BUF_SIZE); //--本来应该用while一直循环,但由于用了libevent,只在可以读的时候才触发on_read(),故不必用while了 int size = read(sock, buffer, BUF_SIZE); if(0 == size){//说明socket关闭 cout<<"read size is 0 for socket:"<<sock<<endl; destroy_sock_ev(event_struct); close(sock); return; } struct sock_ev_write* sock_ev_write_struct = (struct sock_ev_write*)malloc(sizeof(struct sock_ev_write)); sock_ev_write_struct->buffer = buffer; struct event* write_ev = (struct event*)malloc(sizeof(struct event));//发生写事件(也就是只要socket缓冲区可写)时,就将反馈数据通过socket写回客户端 sock_ev_write_struct->write_ev = write_ev; event_set(write_ev, sock, EV_WRITE, on_write, sock_ev_write_struct); event_base_set(event_struct->base, write_ev); event_add(write_ev, NULL); cout<<"on_read() finished, sock="<<sock<<endl;}/** * main执行accept()得到新socket_fd的时候,执行这个方法 * 创建一个新线程,在新线程里反馈给client收到的信息 */void* process_in_new_thread_when_accepted(void* arg){ long long_fd = (long)arg; int fd = (int)long_fd; if(fd<0){ cout<<"process_in_new_thread_when_accepted() quit!"<<endl; return 0; } //-------初始化base,写事件和读事件-------- struct event_base* base = event_base_new(); struct event* read_ev = (struct event*)malloc(sizeof(struct event));//发生读事件后,从socket中取出数据 //-------将base,read_ev,write_ev封装到一个event_struct对象里,便于销毁--------- struct sock_ev* event_struct = (struct sock_ev*)malloc(sizeof(struct sock_ev)); event_struct->base = base; event_struct->read_ev = read_ev; //-----对读事件进行相应的设置------------ event_set(read_ev, fd, EV_READ|EV_PERSIST, on_read, event_struct); event_base_set(base, read_ev); event_add(read_ev, NULL); //--------开始libevent的loop循环----------- event_base_dispatch(base); cout<<"event_base_dispatch() stopped for sock("<<fd<<")"<<" in process_in_new_thread_when_accepted()"<<endl; event_base_free(base); //必须在此删除子线程的base return 0;}/** * 每当accept出一个新的socket_fd时,调用这个方法。 * 创建一个新线程,在新线程里与client做交互 */void accept_new_thread(int sock){ pthread_t thread; pthread_create(&thread,NULL,process_in_new_thread_when_accepted,(void*)sock); pthread_detach(thread);}/** * 每当有新连接连到server时,就通过libevent调用此函数。 * 每个连接对应一个新线程 */void on_accept(int sock, short event, void* arg){ struct sockaddr_in remote_addr; int sin_size=sizeof(struct sockaddr_in); int new_fd = accept(sock, (struct sockaddr*) &remote_addr, (socklen_t*)&sin_size); if(new_fd < 0){ cout<<"Accept error in on_accept()"<<endl; return; } cout<<"new_fd accepted is "<<new_fd<<endl; accept_new_thread(new_fd); cout<<"on_accept() finished for fd="<<new_fd<<endl;}int main(){ int fd = getSocket(); if(fd<0){ cout<<"Error in main(), fd<0"<<endl; } cout<<"main() fd="<<fd<<endl; //----为服务器主线程绑定ip和port------------------------------ struct sockaddr_in local_addr; //服务器端网络地址结构体 memset(&local_addr,0,sizeof(local_addr)); //数据初始化--清零 local_addr.sin_family=AF_INET; //设置为IP通信 local_addr.sin_addr.s_addr=inet_addr(SERVER_IP);//服务器IP地址 local_addr.sin_port=htons(SERVER_PORT); //服务器端口号 int bind_result = bind(fd, (struct sockaddr*) &local_addr, sizeof(struct sockaddr)); if(bind_result < 0){ cout<<"Bind Error in main()"<<endl; return -1; } cout<<"bind_result="<<bind_result<<endl; listen(fd, 10); //-----设置libevent事件,每当socket出现可读事件,就调用on_accept()------------ struct event_base* base = event_base_new(); struct event listen_ev; event_set(&listen_ev, fd, EV_READ|EV_PERSIST, on_accept, NULL); event_base_set(base, &listen_ev); event_add(&listen_ev, NULL); event_base_dispatch(base); //------以下语句理论上是不会走到的--------------------------- cout<<"event_base_dispatch() in main() finished"<<endl; //----销毁资源------------- event_del(&listen_ev); event_base_free(base); cout<<"main() finished"<<endl;}
客户端程序:
#include <iostream>#include <sys/select.h>#include <sys/socket.h>#include <unistd.h>#include <pthread.h>#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string>#include <string.h>#include <event.h>using namespace std;#define BUF_SIZE 1024/** * 连接到server端,如果成功,返回fd,如果失败返回-1 */int connectServer(char* ip, int port){ int fd = socket( AF_INET, SOCK_STREAM, 0 ); cout<<"fd= "<<fd<<endl; if(-1 == fd){ cout<<"Error, connectServer() quit"<<endl; return -1; } struct sockaddr_in remote_addr; //服务器端网络地址结构体 memset(&remote_addr,0,sizeof(remote_addr)); //数据初始化--清零 remote_addr.sin_family=AF_INET; //设置为IP通信 remote_addr.sin_addr.s_addr=inet_addr(ip);//服务器IP地址 remote_addr.sin_port=htons(port); //服务器端口号 int con_result = connect(fd, (struct sockaddr*) &remote_addr, sizeof(struct sockaddr)); if(con_result < 0){ cout<<"Connect Error!"<<endl; close(fd); return -1; } cout<<"con_result="<<con_result<<endl; return fd;}void on_read(int sock, short event, void* arg){ char* buffer = new char[BUF_SIZE]; memset(buffer, 0, sizeof(char)*BUF_SIZE); //--本来应该用while一直循环,但由于用了libevent,只在可以读的时候才触发on_read(),故不必用while了 int size = read(sock, buffer, BUF_SIZE); if(0 == size){//说明socket关闭 cout<<"read size is 0 for socket:"<<sock<<endl; struct event* read_ev = (struct event*)arg; if(NULL != read_ev){ event_del(read_ev); free(read_ev); } close(sock); return; } cout<<"Received from server---"<<buffer<<endl; delete[]buffer;}void* init_read_event(void* arg){ long long_sock = (long)arg; int sock = (int)long_sock; //-----初始化libevent,设置回调函数on_read()------------ struct event_base* base = event_base_new(); struct event* read_ev = (struct event*)malloc(sizeof(struct event));//发生读事件后,从socket中取出数据 event_set(read_ev, sock, EV_READ|EV_PERSIST, on_read, read_ev); event_base_set(base, read_ev); event_add(read_ev, NULL); event_base_dispatch(base); //-------------- event_base_free(base);}/** * 创建一个新线程,在新线程里初始化libevent读事件的相关设置,并开启event_base_dispatch */void init_read_event_thread(int sock){ pthread_t thread; pthread_create(&thread,NULL,init_read_event,(void*)sock); pthread_detach(thread);}int main() { cout << "main started" << endl; // prints Hello World!!! cout << "Please input server IP:"<<endl; char ip[16]; cin >> ip; cout << "Please input port:"<<endl; int port; cin >> port; cout << "ServerIP is "<<ip<<" ,port="<<port<<endl; int socket_fd = connectServer(ip, port); cout << "socket_fd="<<socket_fd<<endl; init_read_event_thread(socket_fd); //-------------------------- char buffer[BUF_SIZE]; bool isBreak = false; while(!isBreak){ cout << "Input your data to server(\'q\' or \"quit\" to exit)"<<endl; //cin >> buffer; cin.getline(buffer,BUF_SIZE); if(strcmp("q", buffer)==0 || strcmp("quit", buffer)==0){ isBreak=true; close(socket_fd); break; } cout << "Your input is "<<buffer<<endl; int write_num = write(socket_fd, buffer, strlen(buffer)); cout << write_num <<" characters written"<<endl; sleep(2); } cout<<"main finished"<<endl; return 0;}
0 0
- 文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题 文章标题 文章标题 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- HDU-ACM2050
- 浅析字母识别的算法
- 原型模式
- 判断一个整系数高阶方程的无理根的个数(区域赛)
- 第三周编程题-奇偶个数
- 文章标题
- 从通讯录中获取联系人的详细信息
- linux文件的创建、编辑常用命令
- 动态添加Fragment
- 第三周编程题-数字特征值
- matlab冒号的用法
- HDU-ACM2051
- NYIST 113 字符串替换
- 结构体位制