用libev的c语言版本实现简单的网络通信服务器

由于最近现网的epoll版本服务器,出现了点诡异的问题,不得已改用libev快速上线,在这里先记录下简单的使用实例。代码中可能存在部分bug,此代码并非线上跑的代码,不过已经五脏俱全,如果有任何疑问,欢迎一起讨论。

转载注明出处:http://blog.csdn.net/lengzijian/article/details/8315133

  1. #include <ev.h>  
  2. #include <stdio.h>  
  3. #include <netinet/in.h>  
  4. #include<stdlib.h>  
  5. #include <string.h>  
  6.   
  7. #define PORT 57789  
  8. #define BUFFER_SIZE 2048  
  9. #define MAX_ALLOWED_CLIENT 10240  
  10.   
  11. struct ev_io *libevlist[MAX_ALLOWED_CLIENT] = {NULL};  
  12.   
  13. void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);  
  14.   
  15. void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);  
  16.   
  17. void timer_beat(struct ev_loop *loop, struct ev_timer *watcher, int revents);  
  18.   
  19. int freelibev(struct ev_loop *loop, int fd);  
  20.   
  21.   
  22. int main()  
  23. {  
  24.     struct ev_loop *loop=ev_default_loop(0);  
  25.     int sd;  
  26.     struct sockaddr_in addr;  
  27.     int addr_len = sizeof(addr);  
  28.       
  29.     //创建一个io watcher和一个timer watcher  
  30.     struct ev_io socket_accept;  
  31.     struct ev_timer timeout_w;  
  32.     //创建socket连接  
  33.     sd = socket(PF_INET, SOCK_STREAM, 0);  
  34.     if(sd < 0)  
  35.     {  
  36.         printf("socket error ");  
  37.         return -1;  
  38.     }  
  39.     bzero(&addr, sizeof(addr));  
  40.     addr.sin_family = AF_INET;  
  41.     addr.sin_port = htons(PORT);  
  42.     addr.sin_addr.s_addr = INADDR_ANY;  
  43.     //正常bind  
  44.     if(bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0)  
  45.     {  
  46.         printf("bind error ");  
  47.         return -1;  
  48.     }  
  49.     //正常listen  
  50.     if(listen(sd, SOMAXCONN) < 0)  
  51.     {  
  52.         printf("listen error ");  
  53.         return -1;  
  54.     }  
  55.     //设置fd可重用  
  56.     int bReuseaddr=1;  
  57.     if(setsockopt(sd,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(bReuseaddr)) != 0)  
  58.     {  
  59.         printf("setsockopt error in reuseaddr[%d] ", sd);  
  60.         return ;  
  61.     }  
  62.       
  63.     //初始化io watcher,用于监听fd  
  64.     ev_io_init(&socket_accept, accept_cb, sd, EV_READ);  
  65.     ev_io_start(loop, &socket_accept);  
  66.       
  67.     //可以向远端发送心跳包  
  68.     //ev_timer_init(&timeout_w, timer_beat, 1., 0.);  
  69.     //ev_timer_start(loop, &timeout_w);  
  70.       
  71.     ev_run(loop, 0);  
  72.       
  73.     return 1;  
  74. }  
  75.   
  76. void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)  
  77. {  
  78.     /* 
  79.         如果有链接,则继续监听fd; 
  80.     */  
  81.     struct sockaddr_in client_addr;  
  82.     socklen_t client_len = sizeof(client_addr);  
  83.     int client_sd;  
  84.     //创建客户端的io watcher  
  85.     struct ev_io *w_client = (struct ev_io*) malloc(sizeof(struct ev_io));  
  86.       
  87.     if(w_client == NULL)  
  88.     {  
  89.         printf("malloc error in accept_cb ");  
  90.         return ;  
  91.     }  
  92.       
  93.     if(EV_ERROR & revents)  
  94.     {  
  95.         printf("error event in accept ");  
  96.         return ;  
  97.     }  
  98.       
  99.     //获取与客户端相连的fd  
  100.     client_sd = accept(watcher->fd, (struct sockaddr*)&client_addr, &client_len);  
  101.     if(client_sd < 0)  
  102.     {  
  103.         printf("accept error ");  
  104.         return;  
  105.     }  
  106.     //如果连接数超出指定范围,则关闭连接  
  107.     if( client_sd > MAX_ALLOWED_CLIENT)  
  108.     {  
  109.         printf("fd too large[%d] ", client_sd);  
  110.         close(client_sd);  
  111.         return ;  
  112.     }  
  113.       
  114.     if(libevlist[client_sd] != NULL)  
  115.     {  
  116.         printf("client_sd not NULL fd is [%d] ", client_sd);  
  117.         return ;  
  118.     }  
  119.       
  120.     printf("client connected ");  
  121.     //监听新的fd  
  122.     ev_io_init(w_client, read_cb, client_sd, EV_READ);  
  123.     ev_io_start(loop, w_client);  
  124.       
  125.     libevlist[client_sd] = w_client;  
  126.   
  127. }  
  128.   
  129. void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)  
  130. {  
  131.     char buffer[BUFFER_SIZE];  
  132.     ssize_t read;  
  133.       
  134.     if(EV_ERROR & revents)  
  135.     {  
  136.         printf("error event in read ");  
  137.         return ;  
  138.     }  
  139.     //正常的recv  
  140.     read = recv(watcher->fd, buffer, BUFFER_SIZE, 0);  
  141.     if(read < 0)  
  142.     {  
  143.         printf("read error ");  
  144.         return;  
  145.     }  
  146.       
  147.     if(read == 0)  
  148.     {  
  149.         printf("client disconnected. ");  
  150.         //ev_io_stop(loop, watcher);  
  151.         //free(watcher);  
  152.         //如果客户端断开连接,释放响应的资源,并且关闭监听  
  153.         freelibev(loop, watcher->fd);  
  154.         return;  
  155.     }  
  156.     else  
  157.     {  
  158.         //buffer[read] = '';  
  159.         printf("receive message:%s ", buffer);  
  160.     }  
  161.     //返回给客户端  
  162.     send(watcher->fd, buffer, read, 0);  
  163.     bzero(buffer, read);  
  164. }  
  165.   
  166. void timer_beat(struct ev_loop *loop, struct ev_timer *watcher, int revents)  
  167. {  
  168.     float timeout = 2.0;  
  169.     //这里可以发送心跳包,也可以什么都不做  
  170.     printf("send beat per[%f] ",timeout);      
  171.     fflush(stdout);  
  172.       
  173.     if(EV_ERROR & revents)  
  174.     {  
  175.         printf("error event in timer_beat ");  
  176.         return ;  
  177.     }  
  178.       
  179.     ev_timer_set(watcher, timeout,0.);  
  180.     ev_timer_start(loop, watcher);  
  181.     return;  
  182. }  
  183.   
  184. int freelibev(struct ev_loop *loop, int fd)  
  185. {  
  186.     /*if(fd > MAX_ALLOWED_CLIENT) 
  187.     { 
  188.         printf("more than MAX_ALLOWED_CLIENT[%d]", fd); 
  189.         return -1; 
  190.     }*/  
  191.     //清理相关资源  
  192.       
  193.     if(libevlist[fd] == NULL)  
  194.     {  
  195.         printf("the fd already freed[%d] ", fd);  
  196.         return -1;  
  197.     }  
  198.       
  199.     close(fd);  
  200.     ev_io_stop(loop, libevlist[fd]);  
  201.     free(libevlist[fd]);  
  202.     libevlist[fd] = NULL;  
  203.     return 1;  
  204. }  


 

makefile:

  1. CC=gcc  
  2. FLAGS=-I. -I/home/lengzijian/c/libev/libev-4.11   
  3. LDFLAGS=-L/usr/lib -L/home/lengzijian/c/libev/libev-4.11/.libs -lev -Wall  
  4.   
  5. OBJECTS=server.o  
  6. ALL_BIN=server  
  7.   
  8. all:$(ALL_BIN)   
  9.   
  10. $(ALL_BIN):$(OBJECTS)   
  11.     $(CC) $(FLAGS) $(LDFLAGS) -o $@ $^  
  12.   
  13.   
  14. %.o:%.c  
  15.     $(CC) -c $< $(FLAGS) $(FLAGS)  
  16.   
  17. clean:  
  18.     rm -fr $(OBJECTS)  
  19.     rm -fr $(ALL_BIN)  


 

注意makefile中的头文件路径,和动态链接库的路径

测试时,只需要telnet ip 57789 即可

原文地址:https://www.cnblogs.com/hzcya1995/p/13318336.html