Libevent使用例子,从简单到复杂
Posted 菜b
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Libevent使用例子,从简单到复杂相关的知识,希望对你有一定的参考价值。
本文从简单到复杂,展示如何使用libevent。网上的许多例子都是只有服务器端的,本文里面客户端和服务器端都有,以飨读者。
关于libevent编程时的一些疑问可以阅读《libevent编程疑难解答》。假如读者还想了解libevent的具体实现,可以阅读《libevent源码分析》系统文章。
不说这么多了,直接上代码。
初等:
客户端代码:
1 #include<sys/types.h> 2 #include<sys/socket.h> 3 #include<netinet/in.h> 4 #include<arpa/inet.h> 5 #include<errno.h> 6 #include<unistd.h> 7 8 #include<stdio.h> 9 #include<string.h> 10 #include<stdlib.h> 11 12 #include<event.h> 13 #include<event2/util.h> 14 15 16 17 18 int tcp_connect_server(const char* server_ip, int port); 19 20 21 void cmd_msg_cb(int fd, short events, void* arg); 22 void socket_read_cb(int fd, short events, void *arg); 23 24 int main(int argc, char** argv) 25 { 26 if( argc < 3 ) 27 { 28 printf("please input 2 parameter\n"); 29 return -1; 30 } 31 32 33 //两个参数依次是服务器端的IP地址、端口号 34 int sockfd = tcp_connect_server(argv[1], atoi(argv[2])); 35 if( sockfd == -1) 36 { 37 perror("tcp_connect error "); 38 return -1; 39 } 40 41 printf("connect to server successful\n"); 42 43 struct event_base* base = event_base_new(); 44 45 struct event *ev_sockfd = event_new(base, sockfd, 46 EV_READ | EV_PERSIST, 47 socket_read_cb, NULL); 48 event_add(ev_sockfd, NULL); 49 50 //监听终端输入事件 51 struct event* ev_cmd = event_new(base, STDIN_FILENO, 52 EV_READ | EV_PERSIST, cmd_msg_cb, 53 (void*)&sockfd); 54 55 56 event_add(ev_cmd, NULL); 57 58 event_base_dispatch(base); 59 60 printf("finished \n"); 61 return 0; 62 } 63 64 65 66 67 68 69 void cmd_msg_cb(int fd, short events, void* arg) 70 { 71 char msg[1024]; 72 73 int ret = read(fd, msg, sizeof(msg)); 74 if( ret <= 0 ) 75 { 76 perror("read fail "); 77 exit(1); 78 } 79 80 int sockfd = *((int*)arg); 81 82 //把终端的消息发送给服务器端 83 //为了简单起见,不考虑写一半数据的情况 84 write(sockfd, msg, ret); 85 } 86 87 88 void socket_read_cb(int fd, short events, void *arg) 89 { 90 char msg[1024]; 91 92 //为了简单起见,不考虑读一半数据的情况 93 int len = read(fd, msg, sizeof(msg)-1); 94 if( len <= 0 ) 95 { 96 perror("read fail "); 97 exit(1); 98 } 99 100 msg[len] = ‘\0‘; 101 102 printf("recv %s from server\n", msg); 103 } 104 105 106 107 typedef struct sockaddr SA; 108 int tcp_connect_server(const char* server_ip, int port) 109 { 110 int sockfd, status, save_errno; 111 struct sockaddr_in server_addr; 112 113 memset(&server_addr, 0, sizeof(server_addr) ); 114 115 server_addr.sin_family = AF_INET; 116 server_addr.sin_port = htons(port); 117 status = inet_aton(server_ip, &server_addr.sin_addr); 118 119 if( status == 0 ) //the server_ip is not valid value 120 { 121 errno = EINVAL; 122 return -1; 123 } 124 125 sockfd = ::socket(PF_INET, SOCK_STREAM, 0); 126 if( sockfd == -1 ) 127 return sockfd; 128 129 130 status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) ); 131 132 if( status == -1 ) 133 { 134 save_errno = errno; 135 ::close(sockfd); 136 errno = save_errno; //the close may be error 137 return -1; 138 } 139 140 evutil_make_socket_nonblocking(sockfd); 141 142 return sockfd; 143 }
服务器端代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<errno.h> 4 5 #include<unistd.h> 6 #include<event.h> 7 8 9 10 void accept_cb(int fd, short events, void* arg); 11 void socket_read_cb(int fd, short events, void *arg); 12 13 int tcp_server_init(int port, int listen_num); 14 15 int main(int argc, char** argv) 16 { 17 18 int listener = tcp_server_init(9999, 10); 19 if( listener == -1 ) 20 { 21 perror(" tcp_server_init error "); 22 return -1; 23 } 24 25 struct event_base* base = event_base_new(); 26 27 //添加监听客户端请求连接事件 28 struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST, 29 accept_cb, base); 30 event_add(ev_listen, NULL); 31 32 33 event_base_dispatch(base); 34 35 return 0; 36 } 37 38 39 40 void accept_cb(int fd, short events, void* arg) 41 { 42 evutil_socket_t sockfd; 43 44 struct sockaddr_in client; 45 socklen_t len = sizeof(client); 46 47 sockfd = ::accept(fd, (struct sockaddr*)&client, &len ); 48 evutil_make_socket_nonblocking(sockfd); 49 50 printf("accept a client %d\n", sockfd); 51 52 struct event_base* base = (event_base*)arg; 53 54 //仅仅是为了动态创建一个event结构体 55 struct event *ev = event_new(NULL, -1, 0, NULL, NULL); 56 //将动态创建的结构体作为event的回调参数 57 event_assign(ev, base, sockfd, EV_READ | EV_PERSIST, 58 socket_read_cb, (void*)ev); 59 60 event_add(ev, NULL); 61 } 62 63 64 void socket_read_cb(int fd, short events, void *arg) 65 { 66 char msg[4096]; 67 struct event *ev = (struct event*)arg; 68 int len = read(fd, msg, sizeof(msg) - 1); 69 70 71 72 if( len <= 0 ) 73 { 74 printf("some error happen when read\n"); 75 event_free(ev); 76 close(fd); 77 return ; 78 } 79 80 msg[len] = ‘\0‘; 81 printf("recv the client msg: %s", msg); 82 83 char reply_msg[4096] = "I have recvieced the msg: "; 84 strcat(reply_msg + strlen(reply_msg), msg); 85 86 write(fd, reply_msg, strlen(reply_msg) ); 87 } 88 89 90 91 typedef struct sockaddr SA; 92 int tcp_server_init(int port, int listen_num) 93 { 94 int errno_save; 95 evutil_socket_t listener; 96 97 listener = ::socket(AF_INET, SOCK_STREAM, 0); 98 if( listener == -1 ) 99 return -1; 100 101 //允许多次绑定同一个地址。要用在socket和bind之间 102 evutil_make_listen_socket_reuseable(listener); 103 104 struct sockaddr_in sin; 105 sin.sin_family = AF_INET; 106 sin.sin_addr.s_addr = 0; 107 sin.sin_port = htons(port); 108 109 if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 ) 110 goto error; 111 112 if( ::listen(listener, listen_num) < 0) 113 goto error; 114 115 116 //跨平台统一接口,将套接字设置为非阻塞状态 117 evutil_make_socket_nonblocking(listener); 118 119 return listener; 120 121 error: 122 errno_save = errno; 123 evutil_closesocket(listener); 124 errno = errno_save; 125 126 return -1; 127 }
中等:
客户端代码:
#include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<errno.h> #include<unistd.h> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<event.h> #include<event2/bufferevent.h> #include<event2/buffer.h> #include<event2/util.h> int tcp_connect_server(const char* server_ip, int port); void cmd_msg_cb(int fd, short events, void* arg); void server_msg_cb(struct bufferevent* bev, void* arg); void event_cb(struct bufferevent *bev, short event, void *arg); int main(int argc, char** argv) { if( argc < 3 ) { printf("please input 2 parameter\n"); return -1; } //两个参数依次是服务器端的IP地址、端口号 int sockfd = tcp_connect_server(argv[1], atoi(argv[2])); if( sockfd == -1) { perror("tcp_connect error "); return -1; } printf("connect to server successful\n"); struct event_base* base = event_base_new(); struct bufferevent* bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE); //监听终端输入事件 struct event* ev_cmd = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, cmd_msg_cb, (void*)bev); event_add(ev_cmd, NULL); //当socket关闭时会用到回调参数 bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void*)ev_cmd); bufferevent_enable(bev, EV_READ | EV_PERSIST); event_base_dispatch(base); printf("finished \n"); return 0; } void cmd_msg_cb(int fd, short events, void* arg) { char msg[1024]; int ret = read(fd, msg, sizeof(msg)); if( ret < 0 ) { perror("read fail "); exit(1); } struct bufferevent* bev = (struct bufferevent*)arg; //把终端的消息发送给服务器端 bufferevent_write(bev, msg, ret); } void server_msg_cb(struct bufferevent* bev, void* arg) { char msg[1024]; size_t len = bufferevent_read(bev, msg, sizeof(msg)); msg[len] = ‘\0‘; printf("recv %s from server\n", msg); } void event_cb(struct bufferevent *bev, short event, void *arg) { if (event & BEV_EVENT_EOF) printf("connection closed\n"); else if (event & BEV_EVENT_ERROR) printf("some other error\n"); //这将自动close套接字和free读写缓冲区 bufferevent_free(bev); struct event *ev = (struct event*)arg; //因为socket已经没有,所以这个event也没有存在的必要了 event_free(ev); } typedef struct sockaddr SA; 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, (SA*)&server_addr, sizeof(server_addr) ); if( status == -1 ) { save_errno = errno; ::close(sockfd); errno = save_errno; //the close may be error return -1; } evutil_make_socket_nonblocking(sockfd); return sockfd; }
服务器端代码:
#include<stdio.h> #include<string.h> #include<errno.h> #include<event.h> #include<event2/bufferevent.h> void accept_cb(int fd, short events, void* arg); void socket_read_cb(bufferevent* bev, void* arg); void event_cb(struct bufferevent *bev, short event, void *arg); int tcp_server_init(int port, int listen_num); int main(int argc, char** argv) { int listener = tcp_server_init(9999, 10); if( listener == -1 ) { perror(" tcp_server_init error "); return -1; } struct event_base* base = event_base_new(); //添加监听客户端请求连接事件 struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST, accept_cb, base); event_add(ev_listen, NULL); event_base_dispatch(base); event_base_free(base); return 0; } void accept_cb(int fd, short events, void* arg) { evutil_socket_t sockfd; struct sockaddr_in client; socklen_t len = sizeof(client); sockfd = ::accept(fd, (struct sockaddr*)&client, &len ); evutil_make_socket_nonblocking(sockfd); printf("accept a client %d\n", sockfd); struct event_base* base = (event_base*)arg; bufferevent* bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, socket_read_cb, NULL, event_cb, arg); bufferevent_enable(bev, EV_READ | EV_PERSIST); } void socket_read_cb(bufferevent* bev, void* arg) { char msg[4096]; size_t len = bufferevent_read(bev, msg, sizeof(msg)); msg[len] = ‘\0‘; printf("recv the client msg: %s", msg); char reply_msg[4096] = "I have recvieced the msg: "; strcat(reply_msg + strlen(reply_msg), msg); bufferevent_write(bev, reply_msg, strlen(reply_msg)); } void event_cb(struct bufferevent *bev, short event, void *arg) { if (event & BEV_EVENT_EOF) printf("connection closed\n"); else if (event & BEV_EVENT_ERROR) printf("some other error\n"); //这将自动close套接字和free读写缓冲区 bufferevent_free(bev); } typedef struct sockaddr SA; int tcp_server_init(int port, int listen_num) { int errno_save; evutil_socket_t listener; listener = ::socket(AF_INET, SOCK_STREAM, 0); if( listener == -1 ) return -1; //允许多次绑定同一个地址。要用在socket和bind之间 evutil_make_listen_socket_reuseable(listener); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; sin.sin_port = htons(port); if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 ) goto error; if( ::listen(listener, listen_num) < 0) goto error; //跨平台统一接口,将套接字设置为非阻塞状态 evutil_make_socket_nonblocking(listener); return listener; error: errno_save = errno; evutil_closesocket(listener); errno = errno_save; return -1; }
高等:
客户端代码:
1 #include<sys/types.h> 2 #include<sys/socket.h> 3 #include<netinet/in.h> 4 #include<arpa/inet.h> 5 #include<errno.h> 6 #include<unistd.h> 7 8 #include<stdio.h> 9 #include<string.h> 10 #include<stdlib.h> 11 12 #include<event.h> 13 #include<event2/bufferevent.h> 14 #include<event2/buffer.h> 15 #include<event2/util.h> 16 17 18 19 20 int tcp_connect_server(const char* server_ip, int port); 21 22 23 void cmd_msg_cb(int fd, short events, void* arg); 24 void server_msg_cb(struct bufferevent* bev, void* arg); 25 void event_cb(struct bufferevent *bev, short event, void *arg); 26 27 int main(int argc, char** argv) 28 { 29 if( argc < 3 ) 30 { 31 //两个参数依次是服务器端的IP地址、端口号 32 printf("please input 2 parameter\n"); 33 return -1; 34 } 35 36 struct event_base *base = event_base_new(); 37 38 struct bufferevent* bev = bufferevent_socket_new(base, -1, 39 BEV_OPT_CLOSE_ON_FREE); 40 41 //监听终端输入事件 42 struct event* ev_cmd = event_new(base, STDIN_FILENO, 43 EV_READ | EV_PERSIST, 44 cmd_msg_cb, (void*)bev); 45 46 47 event_add(ev_cmd, NULL); 48 49 struct sockaddr_in server_addr; 50 51 memset(&server_addr, 0, sizeof(server_addr) ); 52 53 server_addr.sin_family = AF_INET; 54 server_addr.sin_port = htons(atoi(argv[2])); 55 inet_aton(argv[1], &server_addr.sin_addr); 56 57 bufferevent_socket_connect(bev, (struct sockaddr *)&server_addr, 58 sizeof(server_addr)); 59 60 61 bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void*)ev_cmd); 62 bufferevent_enable(bev, EV_READ | EV_PERSIST); 63 64 65 66 event_base_dispatch(base); 67 68 printf("finished \n"); 69 return 0; 70 } 71 72 73 74 75 76 void cmd_msg_cb(int fd, short events, void* arg) 77 { 78 char msg[1024]; 79 80 int ret = read(fd, msg, sizeof(msg)); 81 if( ret < 0 ) 82 { 83 perror("read fail "); 84 exit(1); 85 } 86 87 struct bufferevent* bev = (struct bufferevent*)arg; 88 89 //把终端的消息发送给服务器端 90 bufferevent_write(bev, msg, ret); 91 } 92 93 94 void server_msg_cb(struct bufferevent* bev, void* arg) 95 { 96 char msg[1024]; 97 98 size_t len = bufferevent_read(bev, msg, sizeof(msg)); 99 msg[len] = ‘\0‘; 100 101 printf("recv %s from server\n", msg); 102 } 103 104 105 void event_cb(struct bufferevent *bev, short event, void *arg) 106 { 107 108 if (event & BEV_EVENT_EOF) 109 printf("connection closed\n"); 110 else if (event & BEV_EVENT_ERROR) 111 printf("some other error\n"); 112 else if( event & BEV_EVENT_CONNECTED) 113 { 114 printf("the client has connected to server\n"); 115 return ; 116 } 117 118 //这将自动close套接字和free读写缓冲区 119 bufferevent_free(bev); 120 121 struct event *ev = (struct event*)arg; 122 event_free(ev); 123 }
服务器端代码:
1 #include<netinet/in.h> 2 #include<sys/socket.h> 3 #include<unistd.h> 4 5 #include<stdio.h> 6 #include<string.h> 7 8 #include<event.h> 9 #include<listener.h> 10 #include<bufferevent.h> 11 #include<thread.h> 12 13 14 void listener_cb(evconnlistener *listener, evutil_socket_t fd, 15 struct sockaddr *sock, int socklen, void *arg); 16 17 void socket_read_cb(bufferevent *bev, void *arg); 18 void socket_event_cb(bufferevent *bev, short events, void *arg); 19 20 int main() 21 { 22 //evthread_use_pthreads();//enable threads 23 24 struct sockaddr_in sin; 25 memset(&sin, 0, sizeof(struct sockaddr_in)); 26 sin.sin_family = AF_INET; 27 sin.sin_port = htons(9999); 28 29 event_base *base = event_base_new(); 30 evconnlistener *listener 31 = evconnlistener_new_bind(base, listener_cb, base, 32 LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, 33 10, (struct sockaddr*)&sin, 34 sizeof(struct sockaddr_in)); 35 36 event_base_dispatch(base); 37 38 evconnlistener_free(listener); 39 event_base_free(base); 40 41 return 0; 42 } 43 44 45 //一个新客户端连接上服务器了 46 //当此函数被调用时,libevent已经帮我们accept了这个客户端。该客户端的 47 //文件描述符为fd 48 void listener_cb(evconnlistener *listener, evutil_socket_t fd, 49 struct sockaddr *sock, int socklen, void *arg) 50 { 51 printf("accept a client %d\n", fd); 52 53 event_base *base = (event_base*)arg; 54 55 //为这个客户端分配一个bufferevent 56 bufferevent *bev = bufferevent_socket_new(base, fd, 57 BEV_OPT_CLOSE_ON_FREE); 58 59 bufferevent_setcb(bev, socket_read_cb, NULL, socket_event_cb, NULL); 60 bufferevent_enable(bev, EV_READ | EV_PERSIST); 61 } 62 63 64 void socket_read_cb(bufferevent *bev, void *arg) 65 { 66 char msg[4096]; 67 68 size_t len = bufferevent_read(bev, msg, sizeof(msg)-1 ); 69 70 msg[len] = ‘\0‘; 71 printf("server read the data %s\n", msg); 72 73 char reply[] = "I has read your data"; 74 bufferevent_write(bev, reply, strlen(reply) ); 75 } 76 77 78 void socket_event_cb(bufferevent *bev, short events, void *arg) 79 { 80 if (events & BEV_EVENT_EOF) 81 printf("connection closed\n"); 82 else if (events & BEV_EVENT_ERROR) 83 printf("some other error\n"); 84 85 //这将自动close套接字和free读写缓冲区 86 bufferevent_free(bev); 87 }
以上是关于Libevent使用例子,从简单到复杂的主要内容,如果未能解决你的问题,请参考以下文章