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>
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学习笔记 —— 牛刀小试:简易的响应式服务器的主要内容,如果未能解决你的问题,请参考以下文章