• 用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 即可

  • 相关阅读:
    假设客车的座位数是9行4列,使用二维数组在控制台应用程序中实现简单的客车售票系统。
    用lua求两个数组的交集、并集和补集。
    Lua 将数组中的某些value设置为nil,打印#数组的长度遇到的问题。
    用Lua编写ACM算法竞赛开灯问题
    EXCEL基础
    微服务的服务粒度该如何权衡
    Linux装cudnn
    How To Install Jenkins on Ubuntu 20.04
    获取heidisql保存的密码
    Spring Framework 远程命令执行漏洞复现(CVE202222965)
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318336.html
Copyright © 2020-2023  润新知