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 errorreturn -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 }
转载于:https://www.cnblogs.com/mayingkun/p/7292002.html
Libevent使用例子,从简单到复杂相关推荐
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答...
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
- ExecutorService与Executors例子的简单剖析(转)
对于多线程有了一点了解之后,那么来看看java.lang.concurrent包下面的一些东西.在此之前,我们运行一个线程都是显式调用了 Thread的start()方法.我们用concurrent下 ...
- linux下glew例子,一个简单的GLSL Shader例子
本例子选自OpenGL Shading Language中的第一个Shader例子,使用颜色平滑地表示一个表面的温度.温度及其颜色的范围在应用程序中进行设置. //先看顶点着色器temp.vert: ...
- matlab fft简单小例子,matlabfft简单例子(A simple example of matlabfft).doc
matlabfft简单例子(A simple example of matlabfft) matlabfft简单例子(A simple example of matlabfft) N = 128; N ...
- java http服务端例子_简单的用 Java Socket 编写的 HTTP 服务器应用
/*** SimpleHttpServer.java*/importjava.io.*;importjava.net.*;importjava.util.StringTokenizer;/*** 一个 ...
- Netty5的例子,简单介绍Netty的用法
转自:http://blog.csdn.net/tjbsl/article/details/51038947 这是一个netty快速入门的例子,也是我的学习笔记,比较简单,翻译于官方的文档整理后把所有 ...
- python简单编程例子-python简单实例训练(21~30)
注意:我用的python2.7,大家如果用Python3.0以上的版本,请记得在print()函数哦!如果因为版本问题评论的,不做回复哦!! 21.题目:将一个正整数分解质因数.例如:输入90,打印出 ...
- 异步通信在生活中的例子_AJAX简单异步通信实例分析
本文实例讲述了AJAX简单异步通信的方法.分享给大家供大家参考.具体分析如下: 客户端:向服务器发出一个空请求. 代码如下: XMLHttpRequest var xmlHttp; function ...
- 生活中java继承例子_简单继承例子:java
通用类,来继承出圆和矩形. package circle; public class Geometric { private String color="white"; priva ...
最新文章
- 初识Frida--Android逆向之Java层hook (一)
- PowerBI随笔(4)-关系模型与报表-1
- UML 类之间的几种关系
- php ci rest,在CodeIgniter框架中使用RESTful服务
- JSON | JSON字符串和JSON对象的区别
- 【C++ grammar】C++简化内存模型
- m_pMainWnd = dlg错误解决方法
- Step-by-step to Transformer:深入解析工作原理(以Pytorch机器翻译为例)
- java包的基本使用
- MySQL常用数据类型
- python语言高空坠球_高空坠物打击体验装置制造方法
- 计蒜客 - 守望者的逃离
- 人工智能——自动驾驶仿真软件
- C++查漏补缺之流状态
- PHP文件流下载内容
- Windows 必备纯净软件
- web项目缺少web组件才能与vs一起运行,带razor语法的 asp.net web pages 2.0.0.1
- 你一生要知道的74幅世界名画…
- Java Web-----轮播图的实现
- Jmeter的元件使用介绍:取样器详解
热门文章
- 在eclipse中安装properties插件PropertiesEditor及设置(附图),ASCII码转换成中文
- 两台服务器实现会话共享
- 20145237第六周学习总结
- 基于遗传算法实现自动组卷
- 从Zygote孵化frameworks进程,分析StartActivity流程中intent传递数据的最大值。
- Java中的StringBuilder类功能详解
- 非proguard无法发现jar(已编译)的外部引用错误,(javac + proguard 则会检查)
- 有可能在onPause之前调用onSaveInstanceState
- Fragment 与DialogFragment 相互之间传递数据
- RecyclerView用法--展示多种类型Item数据