本文从简单到复杂,展示如何使用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使用例子,从简单到复杂相关推荐

  1. AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答...

    一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...

  2. ExecutorService与Executors例子的简单剖析(转)

    对于多线程有了一点了解之后,那么来看看java.lang.concurrent包下面的一些东西.在此之前,我们运行一个线程都是显式调用了 Thread的start()方法.我们用concurrent下 ...

  3. linux下glew例子,一个简单的GLSL Shader例子

    本例子选自OpenGL Shading Language中的第一个Shader例子,使用颜色平滑地表示一个表面的温度.温度及其颜色的范围在应用程序中进行设置. //先看顶点着色器temp.vert: ...

  4. matlab fft简单小例子,matlabfft简单例子(A simple example of matlabfft).doc

    matlabfft简单例子(A simple example of matlabfft) matlabfft简单例子(A simple example of matlabfft) N = 128; N ...

  5. java http服务端例子_简单的用 Java Socket 编写的 HTTP 服务器应用

    /*** SimpleHttpServer.java*/importjava.io.*;importjava.net.*;importjava.util.StringTokenizer;/*** 一个 ...

  6. Netty5的例子,简单介绍Netty的用法

    转自:http://blog.csdn.net/tjbsl/article/details/51038947 这是一个netty快速入门的例子,也是我的学习笔记,比较简单,翻译于官方的文档整理后把所有 ...

  7. python简单编程例子-python简单实例训练(21~30)

    注意:我用的python2.7,大家如果用Python3.0以上的版本,请记得在print()函数哦!如果因为版本问题评论的,不做回复哦!! 21.题目:将一个正整数分解质因数.例如:输入90,打印出 ...

  8. 异步通信在生活中的例子_AJAX简单异步通信实例分析

    本文实例讲述了AJAX简单异步通信的方法.分享给大家供大家参考.具体分析如下: 客户端:向服务器发出一个空请求. 代码如下: XMLHttpRequest var xmlHttp; function ...

  9. 生活中java继承例子_简单继承例子:java

    通用类,来继承出圆和矩形. package circle; public class Geometric { private String color="white"; priva ...

最新文章

  1. 初识Frida--Android逆向之Java层hook (一)
  2. PowerBI随笔(4)-关系模型与报表-1
  3. UML 类之间的几种关系
  4. php ci rest,在CodeIgniter框架中使用RESTful服务
  5. JSON | JSON字符串和JSON对象的区别
  6. 【C++ grammar】C++简化内存模型
  7. m_pMainWnd = dlg错误解决方法
  8. Step-by-step to Transformer:深入解析工作原理(以Pytorch机器翻译为例)
  9. java包的基本使用
  10. MySQL常用数据类型
  11. python语言高空坠球_高空坠物打击体验装置制造方法
  12. 计蒜客 - 守望者的逃离
  13. 人工智能——自动驾驶仿真软件
  14. C++查漏补缺之流状态
  15. PHP文件流下载内容
  16. Windows 必备纯净软件
  17. web项目缺少web组件才能与vs一起运行,带razor语法的 asp.net web pages 2.0.0.1
  18. 你一生要知道的74幅世界名画…
  19. Java Web-----轮播图的实现
  20. Jmeter的元件使用介绍:取样器详解

热门文章

  1. 在eclipse中安装properties插件PropertiesEditor及设置(附图),ASCII码转换成中文
  2. 两台服务器实现会话共享
  3. 20145237第六周学习总结
  4. 基于遗传算法实现自动组卷
  5. 从Zygote孵化frameworks进程,分析StartActivity流程中intent传递数据的最大值。
  6. Java中的StringBuilder类功能详解
  7. 非proguard无法发现jar(已编译)的外部引用错误,(javac + proguard 则会检查)
  8. 有可能在onPause之前调用onSaveInstanceState
  9. Fragment 与DialogFragment 相互之间传递数据
  10. RecyclerView用法--展示多种类型Item数据