libevent学习笔记 —— 牛刀小试:简易的响应式服务器

时间:2021-07-18 00:17:29

回想起之前自己用纯c手动写epoll循环,libevent用起来还真是很快捷啊!重写了之前学习的时候的一个例子,分别用纯c与libevent来实现。嗯,为了方便对比一下,就一个文件写到黑了。

纯c版:

一个server.c与client.c共同引用的头文件func.h

libevent学习笔记 —— 牛刀小试:简易的响应式服务器libevent学习笔记 —— 牛刀小试:简易的响应式服务器
 1 #include<stdio.h>
2 #include<string.h>
3 #include<sys/types.h>
4 #include<sys/stat.h>
5 #include<fcntl.h>
6 #include<unistd.h>
7 #include<dirent.h>
8 #include<time.h>
9 #include<pwd.h>
10 #include<grp.h>
11 #include<stdlib.h>
12 #include<sys/time.h>
13 #include<sys/select.h>
14 #include<sys/mman.h>
15 #include<sys/wait.h>
16 #include<sys/ipc.h>
17 #include<sys/shm.h>
18 #include<sys/sem.h>
19 #include<signal.h>
20 #include<pthread.h>
21 #include<netinet/in.h>
22 #include<sys/socket.h>
23 #include<arpa/inet.h>
24 #include<sys/epoll.h>
25 #include<fcntl.h>
View Code

 

client.c

  1  ///
2 /// @file client.c
3 /// @author marrs(chenchengxi993@gmail.com)
4 /// @date 2017-10-19 22:21:01
5 ///
6
7 #include "func.h"
8
9 int socket_init(char * pst_ip, short short_port);
10 int epoll_init(int int_sfd);
11 int epoll_add(int int_sfd, int int_epfd);
12 int epoll_del(int int_sfd, int int_epfd);
13 int epoll_loop(int int_sfd, int int_epfd);
14 int on_send_message_callback(int int_sfd, int int_epfd);
15 int on_recv_message_callback(int int_fd, int int_epfd);
16
17 int main(int argc, char* argv[])
18 {
19 if(argc != 3 )
20 {
21 printf("%s ip port\n",argv[0]);
22 return -1;
23 }
24
25 char * pst_ip = argv[1];
26 short short_port = atoi(argv[2]);
27
28 //初始化socket
29 int int_sfd = socket_init(pst_ip, short_port);
30 if (-1 == int_sfd)
31 {
32 printf("socket init fail...\n");
33 return -1;
34 }
35
36 //初始化epoll
37 int int_epfd = epoll_init(int_sfd);
38
39 //epoll循环
40 epoll_loop(int_sfd, int_epfd);
41 return 0;
42 }
43
44 int socket_init(char * pst_ip, short short_port)
45 {
46 //初始化socket
47 int int_sfd = socket(AF_INET,SOCK_STREAM,0);
48 if(-1 == int_sfd)
49 {
50 perror("socket");
51 return -1;
52 }
53 int int_ret;
54
55 //连接服务器
56 struct sockaddr_in sock_client;
57 sock_client.sin_family = AF_INET;
58 sock_client.sin_addr.s_addr = inet_addr(pst_ip);
59 sock_client.sin_port = htons(short_port);
60
61 printf("prepare to connect ip:%s port:%d\n", pst_ip, short_port);
62 int_ret = connect(int_sfd, (struct sockaddr*)&sock_client, sizeof(sock_client));
63 if(-1 == int_ret)
64 {
65 perror("connect");
66 return -1;
67 }
68 printf("connect ip:%s port:%d success!\n", pst_ip, short_port);
69
70 //修改文件描述符状态为非阻塞
71 int status;
72 status=fcntl(int_sfd,F_GETFL);
73 status=status|O_NONBLOCK;
74 fcntl(int_sfd,F_SETFL,status);
75
76 return int_sfd;
77 }
78
79 int epoll_add(int int_fd, int int_epfd)
80 {
81 struct epoll_event epoll_ev;
82 epoll_ev.events = EPOLLIN|EPOLLET;
83 epoll_ev.data.fd = int_fd;
84 epoll_ctl(int_epfd, EPOLL_CTL_ADD, int_fd, &epoll_ev);
85 return 0;
86 }
87
88 int epoll_del(int int_fd, int int_epfd)
89 {
90 struct epoll_event epoll_ev;
91 epoll_ev.events = EPOLLIN|EPOLLET;
92 epoll_ev.data.fd = int_fd;
93 epoll_ctl(int_epfd, EPOLL_CTL_DEL, int_fd, &epoll_ev);
94 return 0;
95 }
96
97 int epoll_init(int int_sfd)
98 {
99 int int_epfd;
100 int_epfd = epoll_create(1);
101 epoll_add(0, int_epfd);
102 epoll_add(int_sfd, int_epfd);
103 return int_epfd;
104
105 }
106
107 int on_send_message_callback(int int_sfd, int int_epfd)
108 {
109 char pst_buffer[1024];
110 int int_ret;
111 memset(pst_buffer, 0, sizeof(pst_buffer));
112 int_ret = read(0, pst_buffer, sizeof(pst_buffer) - 1);
113 printf("input = %s; ret = %d\n", pst_buffer, int_ret);
114 if(0 == int_ret)
115 {
116 printf("bye~\n");
117 epoll_del(int_sfd, int_epfd);
118 epoll_del(0, int_epfd);
119 return -1;
120 }
121
122 else
123 {
124 printf("send = %s\n", pst_buffer);
125 int_ret = send(int_sfd, (void*)pst_buffer, sizeof(pst_buffer) - 1, 0);
126 if(-1 == int_ret)
127 {
128 perror("send");
129 epoll_del(int_sfd, int_epfd);
130 epoll_del(0, int_epfd);
131 return -1;
132 }
133 printf("send success!\n");
134 }
135 return int_ret;
136 }
137
138 int on_recv_message_callback(int int_fd, int int_epfd)
139 {
140 char pst_buffer[1024];
141 int int_ret;
142 while(1)
143 {
144 memset(pst_buffer, 0, sizeof(pst_buffer));
145 int_ret = recv(int_fd, (void*)pst_buffer, sizeof(pst_buffer) - 1, 0);
146 if(0 > int_ret)
147 {
148 break;
149 }
150 if(0 == int_ret)
151 {
152 printf("The server has been offline\n");
153 epoll_del(int_fd, int_epfd);
154 return -1;
155 }
156 printf("%s", pst_buffer);
157 }
158 printf("\n");
159
160 return 0;
161 }
162
163 int epoll_loop(int int_sfd, int int_epfd)
164 {
165 struct epoll_event epoll_evs[2];
166 int int_ret;
167 int int_event_num;
168 int int_idx;
169 int is_loop = 1;
170
171 //循环体
172 while(is_loop)
173 {
174 memset(epoll_evs, 0, sizeof(epoll_evs));
175
176 //等待事件
177 int_event_num = epoll_wait(int_epfd, epoll_evs, 2, -1);
178 if (int_event_num > 0)
179 {
180 printf("someting in...\n");
181 for(int_idx = 0; int_idx < int_event_num; ++int_idx)
182 {
183 if(epoll_evs[int_idx].events == EPOLLIN)
184 {
185 if(epoll_evs[int_idx].data.fd == 0)
186 {
187 //要发送消息
188 int_ret = on_send_message_callback(int_sfd, int_epfd);
189 if(-1 == int_ret)
190 {
191 printf("on send message callback fail...\n");
192 is_loop = 0;
193 break;
194 }
195
196 if(0 == int_ret)
197 {
198 is_loop = 0;
199 break;
200 }
201 }
202 else if(epoll_evs[int_idx].data.fd == int_sfd)
203 {
204 //收到消息
205 int_ret = on_recv_message_callback(int_sfd, int_epfd);
206 if(-1 == int_ret)
207 {
208 printf("on recv message callback fail...\n");
209 is_loop = 0;
210 break;
211 }
212 }
213 }
214 }
215 }
216 }
217 return 0;
218 }

 

server.c

  1  ///
2 /// @file server.c
3 /// @author marrs(chenchengxi993@gmail.com)
4 /// @date 2017-10-19 21:27:33
5 ///
6
7 #include "func.h"
8
9 int socket_init();
10 int epoll_init(int int_sfd);
11 int epoll_add(int int_sfd, int int_epfd);
12 int epoll_del(int int_sfd, int int_epfd);
13 int epoll_loop(int int_sfd, int int_epfd);
14 int on_accept_callback(int int_sfd, int int_epfd);
15 int on_recv_message_callback(int int_fd, int int_epfd);
16
17 int main()
18 {
19 //初始化socket
20 int int_sfd = socket_init();
21 if (-1 == int_sfd)
22 {
23 printf("socket init fail...\n");
24 return -1;
25 }
26
27 //初始化epoll
28 int int_epfd = epoll_init(int_sfd);
29
30 //进入epoll循环
31 epoll_loop(int_sfd, int_epfd);
32
33 }
34
35 int socket_init()
36 {
37 //初始化socket
38 int int_sfd = socket(AF_INET,SOCK_STREAM,0);
39 int int_ret;
40
41 //绑定ip、port
42 char pst_ip[] = "127.0.0.1";
43 struct sockaddr_in sock_server;
44 sock_server.sin_family = AF_INET;
45 sock_server.sin_addr.s_addr = inet_addr(pst_ip);
46 short int_16_port;
47 for(int_16_port = 2000; int_16_port < 9999; ++int_16_port)
48 {
49 sock_server.sin_port = htons(int_16_port);
50 int_ret = bind(int_sfd, (struct sockaddr*)&sock_server, sizeof(struct sockaddr));
51 if(-1 == int_ret)
52 {
53 printf("bind port = %d fail..retry!\n",int_16_port);
54 continue;
55 }
56 break;
57 }
58
59 if(-1 == int_ret)
60 {
61 perror("bind");
62 return -1;
63 }
64 printf("bind port = %d success!\n",int_16_port);
65
66 //监听
67 int_ret = listen(int_sfd, 10);
68 if(-1 == int_ret)
69 {
70 perror("listen");
71 return -1;
72 }
73
74 return int_sfd;
75 }
76
77 int epoll_add(int int_fd, int int_epfd)
78 {
79 struct epoll_event epoll_ev;
80 epoll_ev.events = EPOLLIN|EPOLLET;
81 epoll_ev.data.fd = int_fd;
82 epoll_ctl(int_epfd, EPOLL_CTL_ADD, int_fd, &epoll_ev);
83 return 0;
84 }
85
86 int epoll_del(int int_fd, int int_epfd)
87 {
88 struct epoll_event epoll_ev;
89 epoll_ev.events = EPOLLIN|EPOLLET;
90 epoll_ev.data.fd = int_fd;
91 epoll_ctl(int_epfd, EPOLL_CTL_DEL, int_fd, &epoll_ev);
92 printf("close fd = %d\n", int_fd);
93 close(int_fd);
94 return 0;
95 }
96
97 int epoll_init(int int_sfd)
98 {
99 int int_epfd;
100 int_epfd = epoll_create(1);
101 epoll_add(int_sfd, int_epfd);
102 return int_epfd;
103
104 }
105
106 int on_accept_callback(int int_sfd, int int_epfd)
107 {
108 struct sockaddr_in sock_client;
109 socklen_t sock_len;
110
111 //接入客户端
112 int int_new_fd = accept(int_sfd, (struct sockaddr*)&sock_client, &sock_len);
113 if(-1 == int_new_fd)
114 {
115 perror("accept");
116 return -1;
117 }
118
119 //把new_fd注册到epfd中
120 epoll_add(int_new_fd, int_epfd);
121
122 //修改文件描述符状态为非阻塞
123 int int_status=fcntl(int_new_fd,F_GETFL);
124 int_status=int_status|O_NONBLOCK;
125 fcntl(int_new_fd,F_SETFL,int_status);
126
127 printf("accept new_fd = %d success!\n", int_new_fd);
128 return int_new_fd;
129 }
130
131 int on_recv_message_callback(int int_fd, int int_epfd)
132 {
133 printf("recv msg from fd = %d\n", int_fd);
134 char pst_buffer[8];
135 int int_ret;
136 while(1)
137 {
138 memset(pst_buffer, 0, sizeof(pst_buffer));
139 int_ret = recv(int_fd, (void*)pst_buffer, sizeof(pst_buffer) - 1, 0);
140 if(0 > int_ret)
141 {
142 break;
143 }
144 if(0 == int_ret)
145 {
146 printf("The client has been offline\n");
147 epoll_del(int_fd, int_epfd);
148 return -1;
149 }
150 printf("%s", pst_buffer);
151 }
152 printf("\n");
153
154 char pst_msg[] = "The server has recv your message...";
155 printf("%ld\n", sizeof(pst_msg));
156
157 int_ret = send(int_fd, (void*)pst_msg, sizeof(pst_msg) - 1, 0);
158 if(-1 == int_ret)
159 {
160 perror("send msg");
161 epoll_del(int_fd,int_epfd);
162 return -1;
163 }
164 printf("%d\n", int_ret);
165
166 return 0;
167 }
168
169 int epoll_loop(int int_sfd, int int_epfd)
170 {
171 struct epoll_event epoll_evs[10];
172 int int_ret;
173 int int_event_num;
174 int int_idx;
175 printf("loop....\n");
176
177 //循环体
178 while(1)
179 {
180 memset(epoll_evs, 0, sizeof(epoll_evs));
181
182 //等待事件
183 int_event_num = epoll_wait(int_epfd, epoll_evs, 10, -1);
184 if (int_event_num > 0)
185 {
186 for(int_idx = 0; int_idx < int_event_num; ++int_idx)
187 {
188 if(epoll_evs[int_idx].events == EPOLLIN)
189 {
190 if(epoll_evs[int_idx].data.fd == int_sfd)
191 {
192 //有新客户端要接入
193 int_ret = on_accept_callback(int_sfd, int_epfd);
194 if(-1 == int_ret)
195 {
196 printf("on accept callback fail...\n");
197 continue;
198 }
199 }
200 else
201 {
202 //收到来自客户端的消息
203 int_ret = on_recv_message_callback(epoll_evs[int_idx].data.fd, int_epfd);
204 if(-1 == int_ret)
205 {
206 printf("on recv message callback fail...\n");
207 continue;
208 }
209 }
210 }
211 }
212 }
213 }
214 }

 

使用libevent:

只需要写回调函数,然后添加到监听的事件集合里就行了。就使用上来说,还是很方便的。

client.c

  1  ///
2 /// @file client.c
3 /// @author marrs(chenchengxi993@gmail.com)
4 /// @date 2017-10-23 21:27:33
5 ///
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <event.h>
16
17 int socket_init(char * pst_ip, short short_port);
18 void on_send_message_callback(int int_fd, __attribute__((unused)) short short_events, void *arg);
19 void on_recv_message_callback(int int_fd, __attribute__((unused)) short short_events, __attribute__((unused)) void *arg);
20
21 int main(int argc, char* argv[])
22 {
23 if(argc != 3 )
24 {
25 printf("%s ip port\n",argv[0]);
26 return -1;
27 }
28
29 char * pst_ip = argv[1];
30 short short_port = atoi(argv[2]);
31
32 //初始化socket
33 int int_sfd = socket_init(pst_ip, short_port);
34 if (-1 == int_sfd)
35 {
36 printf("socket init fail...\n");
37 return -1;
38 }
39
40 //添加监听服务器消息事件
41 struct event_base * base = event_base_new();
42 struct event* event_recv_msg = event_new(base, int_sfd, EV_READ|EV_PERSIST, on_recv_message_callback, NULL);
43 event_add(event_recv_msg, NULL);
44
45 //添加监听终端输入事件
46 struct event* event_send_msg = event_new(base, STDIN_FILENO, EV_READ|EV_PERSIST, on_send_message_callback, (void*)&int_sfd);
47 event_add(event_send_msg, NULL);
48
49 //进入循环
50 event_base_dispatch(base);
51
52 return 0;
53 }
54
55 void on_send_message_callback(int int_fd, __attribute__((unused)) short short_events, void *arg)
56 {
57 char pst_buffer[1024];
58 int int_ret;
59 int int_socket_fd = *(int*)arg;
60 memset(pst_buffer, 0, sizeof(pst_buffer));
61 int_ret = read(int_fd, pst_buffer, sizeof(pst_buffer) - 1);
62 printf("input = %s; ret = %d\n", pst_buffer, int_ret);
63 if(0 == int_ret)
64 {
65 printf("bye~\n");
66 exit(-1);
67 }
68
69 else
70 {
71 printf("send = %s\n", pst_buffer);
72 int_ret = write(int_socket_fd, (void*)pst_buffer, sizeof(pst_buffer) - 1);
73 if(-1 == int_ret)
74 {
75 perror("send");
76 exit(-1);
77 }
78 printf("send success!\n");
79 }
80 }
81
82 void on_recv_message_callback(int int_fd, __attribute__((unused)) short short_events, __attribute__((unused)) void *arg)
83 {
84 char pst_buffer[8];
85 int int_ret;
86 while(1)
87 {
88 memset(pst_buffer, 0, sizeof(pst_buffer));
89 int_ret = recv(int_fd, (void*)pst_buffer, sizeof(pst_buffer) - 1, 0);
90 if(0 > int_ret)
91 {
92 break;
93 }
94 if(0 == int_ret)
95 {
96 printf("The server has been offline\n");
97 exit(-1);
98 }
99 printf("%s", pst_buffer);
100 }
101 printf("\n");
102 }
103
104 int socket_init(char * pst_ip, short short_port)
105 {
106 int int_sfd = socket(AF_INET,SOCK_STREAM,0);
107 if(-1 == int_sfd)
108 {
109 perror("socket");
110 return -1;
111 }
112 int int_ret;
113
114 struct sockaddr_in sock_client;
115 sock_client.sin_family = AF_INET;
116 sock_client.sin_addr.s_addr = inet_addr(pst_ip);
117 sock_client.sin_port = htons(short_port);
118
119 printf("prepare to connect ip:%s port:%d\n", pst_ip, short_port);
120 int_ret = connect(int_sfd, (struct sockaddr*)&sock_client, sizeof(sock_client));
121 if(-1 == int_ret)
122 {
123 perror("connect");
124 return -1;
125 }
126 printf("connect ip:%s port:%d success!\n", pst_ip, short_port);
127 evutil_make_socket_nonblocking(int_sfd);
128 return int_sfd;
129 }

 

server.c

  1  ///
2 /// @file server.c
3 /// @author marrs(chenchengxi993@gmail.com)
4 /// @date 2017-10-22 19:58:15
5 ///
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <event.h>
11 #include <arpa/inet.h>
12
13 int socket_init();
14 void on_accept_callback(int int_fd, __attribute__((unused)) short short_events, void *arg);
15 void on_recv_message(int int_fd, __attribute__((unused)) short short_events, void *arg);
16
17 int main()
18 {
19 //初始化socket
20 int int_sfd = socket_init();
21 if(-1 == int_sfd)
22 {
23 printf("socket init fail...\n");
24 return -1;
25 }
26
27 //初始化struct event_base对象
28 struct event_base * base = event_base_new();
29
30 //添加监听客户端请求连接事件
31 struct event* event_listen = event_new(base, int_sfd, EV_READ|EV_PERSIST, on_accept_callback, base);
32 event_add(event_listen, NULL);
33
34 //进入循环
35 event_base_dispatch(base);
36
37 }
38
39 int socket_init()
40 {
41 int int_ret;
42 short short_port;
43 struct sockaddr_in sock_server;
44
45 //初始化socket
46 evutil_socket_t socket_fd = socket(AF_INET, SOCK_STREAM, 0);
47 if(-1 == socket_fd)
48 {
49 goto error;
50 }
51 printf("get socket fd success\n");
52
53 //允许多次绑定同一个地址
54 evutil_make_listen_socket_reuseable(socket_fd);
55
56 //绑定ip、port
57 sock_server.sin_family = AF_INET;
58 sock_server.sin_addr.s_addr = 0;
59 for(short_port = 2000; short_port < 9999; ++short_port)
60 {
61 sock_server.sin_port = htons(short_port);
62 int_ret = bind(socket_fd, (struct sockaddr*)&sock_server, sizeof(sock_server));
63 if(-1 == int_ret)
64 {
65 continue;
66 }
67 break;
68 }
69 if(-1 == int_ret)
70 {
71 goto error;
72 }
73
74 printf("bind port = %d success\n", short_port);
75
76 //监听
77 int_ret = listen(socket_fd, 10);
78 if(-1 == int_ret)
79 {
80 goto error;
81 }
82 printf("listen success\n");
83
84 //修改文件描述符状态为非阻塞
85 evutil_make_socket_nonblocking(socket_fd);
86 return socket_fd;
87
88 //error
89 error:
90 perror("socket init");
91 evutil_closesocket(socket_fd);
92 return -1;
93 }
94
95 void on_accept_callback(int int_fd, __attribute__((unused))short short_events, void *arg)
96 {
97 evutil_socket_t socket_fd;
98 struct sockaddr_in sock_client;
99 socklen_t sock_len;
100
101 //接入
102 socket_fd = accept(int_fd, (struct sockaddr*)&sock_client, &sock_len);
103 if(-1 == socket_fd)
104 {
105 perror("accept");
106 return;
107 }
108 printf("accpet a new client...\n");
109
110 //修改文件描述符状态为非阻塞
111 evutil_make_socket_nonblocking(socket_fd);
112
113 //添加监听客户端发送消息事件
114 struct event_base* base = (struct event_base*)arg;
115 struct event* event_client = event_new(NULL, -1, 0, NULL, NULL);
116 event_assign(event_client, base, socket_fd, EV_READ|EV_PERSIST, on_recv_message, (void*)event_client);
117 event_add(event_client, NULL);
118
119 }
120
121 void on_recv_message(int int_fd, __attribute__((unused))short short_events, void *arg)
122 {
123 char pst_buffer[8];
124 int int_ret;
125 struct event *event_client = (struct event*)arg;
126 while(1)
127 {
128 memset(pst_buffer, 0, sizeof(pst_buffer));
129 int_ret = read(int_fd, (void*)pst_buffer, sizeof(pst_buffer) - 1);
130 if(0 == int_ret)
131 {
132 printf("the client has been offline...\n");
133 event_free(event_client);
134 close(int_fd);
135 return;
136 }
137 else if(0 > int_ret)
138 {
139 break;
140 }
141 else
142 {
143 printf("%s", pst_buffer);
144 }
145 }
146 printf("\n");
147
148 char pst_msg[] = "the server has recv your msg....";
149 int_ret = write(int_fd, pst_msg, strlen(pst_msg));
150 }