• Libevent使用例子,从简单到复杂


           本文从简单到复杂,展示如何使用libevent。网上的许多例子都是只有服务器端的,本文里面客户端和服务器端都有,以飨读者。

            关于libevent编程时的一些疑问可以阅读《libevent编程疑难解答》。假如读者还想了解libevent的具体实现,可以阅读《libevent源码分析》系统文章。

            不说这么多了,直接上代码。

            

    初等:

    客户端代码:

      1 #include<sys/types.h>
      2 #include<sys/socket.h>
      3 #include<netinet/in.h>
      4 #include<arpa/inet.h>
      5 #include<errno.h>
      6 #include<unistd.h>
      7 
      8 #include<stdio.h>
      9 #include<string.h>
     10 #include<stdlib.h>
     11 
     12 #include<event.h>
     13 #include<event2/util.h>
     14 
     15 
     16 
     17 
     18 int tcp_connect_server(const char* server_ip, int port);
     19 
     20 
     21 void cmd_msg_cb(int fd, short events, void* arg);
     22 void socket_read_cb(int fd, short events, void *arg);
     23 
     24 int main(int argc, char** argv)
     25 {
     26     if( argc < 3 )
     27     {
     28         printf("please input 2 parameter
    ");
     29         return -1;
     30     }
     31 
     32 
     33     //两个参数依次是服务器端的IP地址、端口号
     34     int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));
     35     if( sockfd == -1)
     36     {
     37         perror("tcp_connect error ");
     38         return -1;
     39     }
     40 
     41     printf("connect to server successful
    ");
     42 
     43     struct event_base* base = event_base_new();
     44 
     45     struct event *ev_sockfd = event_new(base, sockfd,
     46                                         EV_READ | EV_PERSIST,
     47                                         socket_read_cb, NULL);
     48     event_add(ev_sockfd, NULL);
     49 
     50     //监听终端输入事件
     51     struct event* ev_cmd = event_new(base, STDIN_FILENO,
     52                                       EV_READ | EV_PERSIST, cmd_msg_cb,
     53                                       (void*)&sockfd);
     54 
     55 
     56     event_add(ev_cmd, NULL);
     57 
     58     event_base_dispatch(base);
     59 
     60     printf("finished 
    ");
     61     return 0;
     62 }
     63 
     64 
     65 
     66 
     67 
     68 
     69 void cmd_msg_cb(int fd, short events, void* arg)
     70 {
     71     char msg[1024];
     72 
     73     int ret = read(fd, msg, sizeof(msg));
     74     if( ret <= 0 )
     75     {
     76         perror("read fail ");
     77         exit(1);
     78     }
     79 
     80     int sockfd = *((int*)arg);
     81 
     82     //把终端的消息发送给服务器端
     83     //为了简单起见,不考虑写一半数据的情况
     84     write(sockfd, msg, ret);
     85 }
     86 
     87 
     88 void socket_read_cb(int fd, short events, void *arg)
     89 {
     90     char msg[1024];
     91 
     92     //为了简单起见,不考虑读一半数据的情况
     93     int len = read(fd, msg, sizeof(msg)-1);
     94     if( len <= 0 )
     95     {
     96         perror("read fail ");
     97         exit(1);
     98     }
     99 
    100     msg[len] = '';
    101 
    102     printf("recv %s from server
    ", msg);
    103 }
    104 
    105 
    106 
    107 typedef struct sockaddr SA;
    108 int tcp_connect_server(const char* server_ip, int port)
    109 {
    110     int sockfd, status, save_errno;
    111     struct sockaddr_in server_addr;
    112 
    113     memset(&server_addr, 0, sizeof(server_addr) );
    114 
    115     server_addr.sin_family = AF_INET;
    116     server_addr.sin_port = htons(port);
    117     status = inet_aton(server_ip, &server_addr.sin_addr);
    118 
    119     if( status == 0 ) //the server_ip is not valid value
    120     {
    121         errno = EINVAL;
    122         return -1;
    123     }
    124 
    125     sockfd = ::socket(PF_INET, SOCK_STREAM, 0);
    126     if( sockfd == -1 )
    127         return sockfd;
    128 
    129 
    130     status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) );
    131 
    132     if( status == -1 )
    133     {
    134         save_errno = errno;
    135         ::close(sockfd);
    136         errno = save_errno; //the close may be error
    137         return -1;
    138     }
    139 
    140     evutil_make_socket_nonblocking(sockfd);
    141 
    142     return sockfd;
    143 }

    服务器端代码:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<errno.h>
      4 
      5 #include<unistd.h>
      6 #include<event.h>
      7 
      8 
      9 
     10 void accept_cb(int fd, short events, void* arg);
     11 void socket_read_cb(int fd, short events, void *arg);
     12 
     13 int tcp_server_init(int port, int listen_num);
     14 
     15 int main(int argc, char** argv)
     16 {
     17 
     18     int listener = tcp_server_init(9999, 10);
     19     if( listener == -1 )
     20     {
     21         perror(" tcp_server_init error ");
     22         return -1;
     23     }
     24 
     25     struct event_base* base = event_base_new();
     26 
     27     //添加监听客户端请求连接事件
     28     struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,
     29                                         accept_cb, base);
     30     event_add(ev_listen, NULL);
     31 
     32 
     33     event_base_dispatch(base);
     34 
     35     return 0;
     36 }
     37 
     38 
     39 
     40 void accept_cb(int fd, short events, void* arg)
     41 {
     42     evutil_socket_t sockfd;
     43 
     44     struct sockaddr_in client;
     45     socklen_t len = sizeof(client);
     46 
     47     sockfd = ::accept(fd, (struct sockaddr*)&client, &len );
     48     evutil_make_socket_nonblocking(sockfd);
     49 
     50     printf("accept a client %d
    ", sockfd);
     51 
     52     struct event_base* base = (event_base*)arg;
     53 
     54     //仅仅是为了动态创建一个event结构体
     55     struct event *ev = event_new(NULL, -1, 0, NULL, NULL);
     56     //将动态创建的结构体作为event的回调参数
     57     event_assign(ev, base, sockfd, EV_READ | EV_PERSIST,
     58                  socket_read_cb, (void*)ev);
     59 
     60     event_add(ev, NULL);
     61 }
     62 
     63 
     64 void socket_read_cb(int fd, short events, void *arg)
     65 {
     66     char msg[4096];
     67     struct event *ev = (struct event*)arg;
     68     int len = read(fd, msg, sizeof(msg) - 1);
     69 
     70 
     71 
     72     if( len <= 0 )
     73     {
     74         printf("some error happen when read
    ");
     75         event_free(ev);
     76         close(fd);
     77         return ;
     78     }
     79 
     80     msg[len] = '';
     81     printf("recv the client msg: %s", msg);
     82 
     83     char reply_msg[4096] = "I have recvieced the msg: ";
     84     strcat(reply_msg + strlen(reply_msg), msg);
     85 
     86     write(fd, reply_msg, strlen(reply_msg) );
     87 }
     88 
     89 
     90 
     91 typedef struct sockaddr SA;
     92 int tcp_server_init(int port, int listen_num)
     93 {
     94     int errno_save;
     95     evutil_socket_t listener;
     96 
     97     listener = ::socket(AF_INET, SOCK_STREAM, 0);
     98     if( listener == -1 )
     99         return -1;
    100 
    101     //允许多次绑定同一个地址。要用在socket和bind之间
    102     evutil_make_listen_socket_reuseable(listener);
    103 
    104     struct sockaddr_in sin;
    105     sin.sin_family = AF_INET;
    106     sin.sin_addr.s_addr = 0;
    107     sin.sin_port = htons(port);
    108 
    109     if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
    110         goto error;
    111 
    112     if( ::listen(listener, listen_num) < 0)
    113         goto error;
    114 
    115 
    116     //跨平台统一接口,将套接字设置为非阻塞状态
    117     evutil_make_socket_nonblocking(listener);
    118 
    119     return listener;
    120 
    121     error:
    122         errno_save = errno;
    123         evutil_closesocket(listener);
    124         errno = errno_save;
    125 
    126         return -1;
    127 }

    中等:

    客户端代码:

    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<arpa/inet.h>
    #include<errno.h>
    #include<unistd.h>
    
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    
    #include<event.h>
    #include<event2/bufferevent.h>
    #include<event2/buffer.h>
    #include<event2/util.h>
    
    
    
    
    int tcp_connect_server(const char* server_ip, int port);
    
    
    void cmd_msg_cb(int fd, short events, void* arg);
    void server_msg_cb(struct bufferevent* bev, void* arg);
    void event_cb(struct bufferevent *bev, short event, void *arg);
    
    int main(int argc, char** argv)
    {
        if( argc < 3 )
        {
            printf("please input 2 parameter
    ");
            return -1;
        }
    
    
        //两个参数依次是服务器端的IP地址、端口号
        int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));
        if( sockfd == -1)
        {
            perror("tcp_connect error ");
            return -1;
        }
    
        printf("connect to server successful
    ");
    
        struct event_base* base = event_base_new();
    
        struct bufferevent* bev = bufferevent_socket_new(base, sockfd,
                                                         BEV_OPT_CLOSE_ON_FREE);
    
        //监听终端输入事件
        struct event* ev_cmd = event_new(base, STDIN_FILENO,
                                          EV_READ | EV_PERSIST, cmd_msg_cb,
                                          (void*)bev);
        event_add(ev_cmd, NULL);
    
        //当socket关闭时会用到回调参数
        bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void*)ev_cmd);
        bufferevent_enable(bev, EV_READ | EV_PERSIST);
    
    
        event_base_dispatch(base);
    
        printf("finished 
    ");
        return 0;
    }
    
    
    
    
    
    
    void cmd_msg_cb(int fd, short events, void* arg)
    {
        char msg[1024];
    
        int ret = read(fd, msg, sizeof(msg));
        if( ret < 0 )
        {
            perror("read fail ");
            exit(1);
        }
    
        struct bufferevent* bev = (struct bufferevent*)arg;
    
        //把终端的消息发送给服务器端
        bufferevent_write(bev, msg, ret);
    }
    
    
    void server_msg_cb(struct bufferevent* bev, void* arg)
    {
        char msg[1024];
    
        size_t len = bufferevent_read(bev, msg, sizeof(msg));
        msg[len] = '';
    
        printf("recv %s from server
    ", msg);
    }
    
    
    void event_cb(struct bufferevent *bev, short event, void *arg)
    {
    
        if (event & BEV_EVENT_EOF)
            printf("connection closed
    ");
        else if (event & BEV_EVENT_ERROR)
            printf("some other error
    ");
    
        //这将自动close套接字和free读写缓冲区
        bufferevent_free(bev);
    
        struct event *ev = (struct event*)arg;
        //因为socket已经没有,所以这个event也没有存在的必要了
        event_free(ev);
    }
    
    
    typedef struct sockaddr SA;
    int tcp_connect_server(const char* server_ip, int port)
    {
        int sockfd, status, save_errno;
        struct sockaddr_in server_addr;
    
        memset(&server_addr, 0, sizeof(server_addr) );
    
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(port);
        status = inet_aton(server_ip, &server_addr.sin_addr);
    
        if( status == 0 ) //the server_ip is not valid value
        {
            errno = EINVAL;
            return -1;
        }
    
        sockfd = ::socket(PF_INET, SOCK_STREAM, 0);
        if( sockfd == -1 )
            return sockfd;
    
    
        status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) );
    
        if( status == -1 )
        {
            save_errno = errno;
            ::close(sockfd);
            errno = save_errno; //the close may be error
            return -1;
        }
    
        evutil_make_socket_nonblocking(sockfd);
    
        return sockfd;
    }

    服务器端代码:

    #include<stdio.h>
    #include<string.h>
    #include<errno.h>
    
    #include<event.h>
    #include<event2/bufferevent.h>
    
    
    
    void accept_cb(int fd, short events, void* arg);
    void socket_read_cb(bufferevent* bev, void* arg);
    void event_cb(struct bufferevent *bev, short event, void *arg);
    int tcp_server_init(int port, int listen_num);
    
    int main(int argc, char** argv)
    {
    
        int listener = tcp_server_init(9999, 10);
        if( listener == -1 )
        {
            perror(" tcp_server_init error ");
            return -1;
        }
    
        struct event_base* base = event_base_new();
    
        //添加监听客户端请求连接事件
        struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,
                                            accept_cb, base);
        event_add(ev_listen, NULL);
    
    
        event_base_dispatch(base);
        event_base_free(base);
    
    
        return 0;
    }
    
    
    
    void accept_cb(int fd, short events, void* arg)
    {
        evutil_socket_t sockfd;
    
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
    
        sockfd = ::accept(fd, (struct sockaddr*)&client, &len );
        evutil_make_socket_nonblocking(sockfd);
    
        printf("accept a client %d
    ", sockfd);
    
        struct event_base* base = (event_base*)arg;
    
        bufferevent* bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE);
        bufferevent_setcb(bev, socket_read_cb, NULL, event_cb, arg);
    
        bufferevent_enable(bev, EV_READ | EV_PERSIST);
    }
    
    
    
    void socket_read_cb(bufferevent* bev, void* arg)
    {
        char msg[4096];
    
        size_t len = bufferevent_read(bev, msg, sizeof(msg));
    
        msg[len] = '';
        printf("recv the client msg: %s", msg);
    
    
        char reply_msg[4096] = "I have recvieced the msg: ";
    
        strcat(reply_msg + strlen(reply_msg), msg);
        bufferevent_write(bev, reply_msg, strlen(reply_msg));
    }
    
    
    
    void event_cb(struct bufferevent *bev, short event, void *arg)
    {
    
        if (event & BEV_EVENT_EOF)
            printf("connection closed
    ");
        else if (event & BEV_EVENT_ERROR)
            printf("some other error
    ");
    
        //这将自动close套接字和free读写缓冲区
        bufferevent_free(bev);
    }
    
    
    typedef struct sockaddr SA;
    int tcp_server_init(int port, int listen_num)
    {
        int errno_save;
        evutil_socket_t listener;
    
        listener = ::socket(AF_INET, SOCK_STREAM, 0);
        if( listener == -1 )
            return -1;
    
        //允许多次绑定同一个地址。要用在socket和bind之间
        evutil_make_listen_socket_reuseable(listener);
    
        struct sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = 0;
        sin.sin_port = htons(port);
    
        if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
            goto error;
    
        if( ::listen(listener, listen_num) < 0)
            goto error;
    
    
        //跨平台统一接口,将套接字设置为非阻塞状态
        evutil_make_socket_nonblocking(listener);
    
        return listener;
    
        error:
            errno_save = errno;
            evutil_closesocket(listener);
            errno = errno_save;
    
            return -1;
    }

    高等:

    客户端代码:

      1 #include<sys/types.h>
      2 #include<sys/socket.h>
      3 #include<netinet/in.h>
      4 #include<arpa/inet.h>
      5 #include<errno.h>
      6 #include<unistd.h>
      7 
      8 #include<stdio.h>
      9 #include<string.h>
     10 #include<stdlib.h>
     11 
     12 #include<event.h>
     13 #include<event2/bufferevent.h>
     14 #include<event2/buffer.h>
     15 #include<event2/util.h>
     16 
     17 
     18 
     19 
     20 int tcp_connect_server(const char* server_ip, int port);
     21 
     22 
     23 void cmd_msg_cb(int fd, short events, void* arg);
     24 void server_msg_cb(struct bufferevent* bev, void* arg);
     25 void event_cb(struct bufferevent *bev, short event, void *arg);
     26 
     27 int main(int argc, char** argv)
     28 {
     29     if( argc < 3 )
     30     {
     31         //两个参数依次是服务器端的IP地址、端口号
     32         printf("please input 2 parameter
    ");
     33         return -1;
     34     }
     35 
     36     struct event_base *base = event_base_new();
     37 
     38     struct bufferevent* bev = bufferevent_socket_new(base, -1,
     39                                                      BEV_OPT_CLOSE_ON_FREE);
     40 
     41     //监听终端输入事件
     42     struct event* ev_cmd = event_new(base, STDIN_FILENO,
     43                                      EV_READ | EV_PERSIST,
     44                                      cmd_msg_cb, (void*)bev);
     45 
     46 
     47     event_add(ev_cmd, NULL);
     48 
     49     struct sockaddr_in server_addr;
     50 
     51     memset(&server_addr, 0, sizeof(server_addr) );
     52 
     53     server_addr.sin_family = AF_INET;
     54     server_addr.sin_port = htons(atoi(argv[2]));
     55     inet_aton(argv[1], &server_addr.sin_addr);
     56 
     57     bufferevent_socket_connect(bev, (struct sockaddr *)&server_addr,
     58                                sizeof(server_addr));
     59 
     60 
     61     bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void*)ev_cmd);
     62     bufferevent_enable(bev, EV_READ | EV_PERSIST);
     63 
     64 
     65 
     66     event_base_dispatch(base);
     67 
     68     printf("finished 
    ");
     69     return 0;
     70 }
     71 
     72 
     73 
     74 
     75 
     76 void cmd_msg_cb(int fd, short events, void* arg)
     77 {
     78     char msg[1024];
     79 
     80     int ret = read(fd, msg, sizeof(msg));
     81     if( ret < 0 )
     82     {
     83         perror("read fail ");
     84         exit(1);
     85     }
     86 
     87     struct bufferevent* bev = (struct bufferevent*)arg;
     88 
     89     //把终端的消息发送给服务器端
     90     bufferevent_write(bev, msg, ret);
     91 }
     92 
     93 
     94 void server_msg_cb(struct bufferevent* bev, void* arg)
     95 {
     96     char msg[1024];
     97 
     98     size_t len = bufferevent_read(bev, msg, sizeof(msg));
     99     msg[len] = '';
    100 
    101     printf("recv %s from server
    ", msg);
    102 }
    103 
    104 
    105 void event_cb(struct bufferevent *bev, short event, void *arg)
    106 {
    107 
    108     if (event & BEV_EVENT_EOF)
    109         printf("connection closed
    ");
    110     else if (event & BEV_EVENT_ERROR)
    111         printf("some other error
    ");
    112     else if( event & BEV_EVENT_CONNECTED)
    113     {
    114         printf("the client has connected to server
    ");
    115         return ;
    116     }
    117 
    118     //这将自动close套接字和free读写缓冲区
    119     bufferevent_free(bev);
    120 
    121     struct event *ev = (struct event*)arg;
    122     event_free(ev);
    123 }

    服务器端代码:

     1 #include<netinet/in.h>  
     2 #include<sys/socket.h>  
     3 #include<unistd.h>  
     4   
     5 #include<stdio.h>  
     6 #include<string.h>  
     7   
     8 #include<event.h>  
     9 #include<listener.h>  
    10 #include<bufferevent.h>  
    11 #include<thread.h>  
    12   
    13   
    14 void listener_cb(evconnlistener *listener, evutil_socket_t fd,  
    15                  struct sockaddr *sock, int socklen, void *arg);  
    16   
    17 void socket_read_cb(bufferevent *bev, void *arg);  
    18 void socket_event_cb(bufferevent *bev, short events, void *arg);  
    19   
    20 int main()  
    21 {  
    22     //evthread_use_pthreads();//enable threads  
    23   
    24     struct sockaddr_in sin;  
    25     memset(&sin, 0, sizeof(struct sockaddr_in));  
    26     sin.sin_family = AF_INET;  
    27     sin.sin_port = htons(9999);  
    28   
    29     event_base *base = event_base_new();  
    30     evconnlistener *listener  
    31             = evconnlistener_new_bind(base, listener_cb, base,  
    32                                       LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,  
    33                                       10, (struct sockaddr*)&sin,  
    34                                       sizeof(struct sockaddr_in));  
    35   
    36     event_base_dispatch(base);  
    37   
    38     evconnlistener_free(listener);  
    39     event_base_free(base);  
    40   
    41     return 0;  
    42 }  
    43   
    44   
    45 //一个新客户端连接上服务器了  
    46 //当此函数被调用时,libevent已经帮我们accept了这个客户端。该客户端的
    47 //文件描述符为fd
    48 void listener_cb(evconnlistener *listener, evutil_socket_t fd,  
    49                  struct sockaddr *sock, int socklen, void *arg)  
    50 {  
    51     printf("accept a client %d
    ", fd);  
    52   
    53     event_base *base = (event_base*)arg;  
    54   
    55     //为这个客户端分配一个bufferevent  
    56     bufferevent *bev =  bufferevent_socket_new(base, fd,  
    57                                                BEV_OPT_CLOSE_ON_FREE);  
    58   
    59     bufferevent_setcb(bev, socket_read_cb, NULL, socket_event_cb, NULL);  
    60     bufferevent_enable(bev, EV_READ | EV_PERSIST);  
    61 }  
    62   
    63   
    64 void socket_read_cb(bufferevent *bev, void *arg)  
    65 {  
    66     char msg[4096];  
    67   
    68     size_t len = bufferevent_read(bev, msg, sizeof(msg)-1 );  
    69   
    70     msg[len] = '';  
    71     printf("server read the data %s
    ", msg);  
    72   
    73     char reply[] = "I has read your data";  
    74     bufferevent_write(bev, reply, strlen(reply) );  
    75 }  
    76   
    77   
    78 void socket_event_cb(bufferevent *bev, short events, void *arg)  
    79 {  
    80     if (events & BEV_EVENT_EOF)  
    81         printf("connection closed
    ");  
    82     else if (events & BEV_EVENT_ERROR)  
    83         printf("some other error
    ");  
    84   
    85     //这将自动close套接字和free读写缓冲区  
    86     bufferevent_free(bev);  
    87 }  
  • 相关阅读:
    Jenkins服务器磁盘空间爆满问题解决
    U3D GPU蒙皮
    关于STRUCT优化的一个点
    UNITY优化资料收集
    U3D的结构体堆分配栈分配
    【转】UGUI研究院之缓存策略让UI打开更快(三十)
    关于U3D场景烘焙的一个想法
    【摘】如果医生给你的孩子开这些药,请主动说不!
    【转】投影矩阵的推导
    Optimizing graphics performance
  • 原文地址:https://www.cnblogs.com/mayingkun/p/7292002.html
Copyright © 2020-2023  润新知