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

Posted 曾经时光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了libevent学习笔记 —— 牛刀小试:简易的响应式服务器相关的知识,希望对你有一定的参考价值。

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

纯c版:

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

技术分享
 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([email protected])
  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([email protected])
  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([email protected])
  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([email protected])
  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 }

 

以上是关于libevent学习笔记 —— 牛刀小试:简易的响应式服务器的主要内容,如果未能解决你的问题,请参考以下文章

Libevent 学习笔记 ——Libevent 2.0安装与简单演示样例

Mybatis学习笔记之一——牛刀小试

libevent学习笔记 —— 第一个程序:计时器

libev学习笔记

libevent的入门学习-库的安装

小白自我提高学习设计模式笔记—装饰者模式在Android开发的小试