• 处理大并发之 对libevent的初步认识


    首先翻译下http://www.wangafu.net/~nickm/libevent-book/01_intro.html里的一段文章

    对异步IO的一个简要介绍

    大多数应用程序都是阻塞的IO调用,如果IO调用是同步(阻塞)的,它不能立即返回直到它的操作完成,或者经过了很长时间直到网络栈丢弃。当你在一个TCP连接上调用”connect()”时,例如,你的操作系统从TCP连接的另一端主机排队等待一个SYN包时。它不能立即返回你的应用程序,直到从连接的另一端主机收到SYN ACK包,或者经历了足够的时候,驱动层丢弃。

    libevent简要介绍

    Libevent是一个轻量级的开源高性能网络库。

    Libevent特点: (来自http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html )
    (1)事件驱动(event-driven),高性能;
    (2)轻量级,专注于网络,不如 ACE 那么臃肿庞大; 
    (3)源代码相当精炼、易
    (4)跨平台,支持 WindowsLinux*BSD和 Mac Os 
    (5)支持多种 I/O多路复用技术,epollpolldev/pollselect kqueue 等; 
    (6)支持 I/O,定时器和信号等事件; 
    (7)注册事件优先级; 
     Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、 Vomi t、 Nylon、 Netchat等等。

    至目前为止资料也看了一部分,源码也看了一部分,我觉得研究源码,查资料,分析源码都很重要,但是最关键的是做demo分析demo

    现在想使用libevent做一个服务端的程序,结合之前使用epoll做的客户端程序做测试。

    刚开始的时候在网上找了一个demo,结果编译不过,折腾半天还是放弃了。

    郁闷了半天,找到一个例子不错,分享出来,我自己分析了下,修改了一些细节然后加了些注释,代码来源于:http://www.felix021.com/blog/read.php?2068 (尊重原创)

    对了,这里不在陈述libevent的安装,之前在研究memcache里有相应的介绍,链接:

    其实安装基本都是./configure –prefix=路径,然后make && make install就可以了

    服务端demo代码:libevent_server.c

    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <errno.h>  
    4.   
    5. #include <event2/event.h>  
    6. #include <event2/bufferevent.h>  
    7.   
    8. #define LISTEN_PORT 8000  
    9. #define LISTEN_BACKLOG 32  
    10.   
    11. void do_accept_cb(evutil_socket_t listener, short event, void *arg);  
    12. void read_cb(struct bufferevent *bev, void *arg);  
    13. void error_cb(struct bufferevent *bev, short event, void *arg);  
    14. void write_cb(struct bufferevent *bev, void *arg);  
    15.   
    16. int main(int argc, char *argv[])  
    17. {  
    18.     int ret;  
    19.     evutil_socket_t listener;  
    20.     listener = socket(AF_INET, SOCK_STREAM, 0);  
    21.     if(listener < 0)  
    22.     {  
    23.         printf("socket error! ");  
    24.         return 1;  
    25.     }  
    26.   
    27.     evutil_make_listen_socket_reuseable(listener);//端口重用,查看源码evutil.c中可以知道就是对setsockopt做了层封装,之所以这样做是因为为了和Win32 networking API兼容  
    28.   
    29.     struct sockaddr_in sin;  
    30.     sin.sin_family = AF_INET;  
    31.     sin.sin_addr.s_addr=htonl(INADDR_ANY);  
    32.     sin.sin_addr.s_addr=inet_addr("127.0.0.1");  
    33.     sin.sin_port = htons(LISTEN_PORT);  
    34.   
    35.     if (bind(listener, (struct sockaddr *)&sin, sizeof(sin)) < 0) {  
    36.         perror("bind");  
    37.         return 1;  
    38.     }  
    39.   
    40.     if (listen(listener, LISTEN_BACKLOG) < 0) {  
    41.         perror("listen");  
    42.         return 1;  
    43.     }  
    44.   
    45.   printf ("Listening... ");  
    46.     
    47.   evutil_make_socket_nonblocking(listener);//设置为非阻塞模式,查看源码evutil.c中可以知道就是对fcntl做了层封装  
    48.     
    49.       struct event_base *base = event_base_new();//创建一个event_base对象也既是创建了一个新的libevent实例  
    50.       if (!base) {  
    51.           fprintf(stderr, "Could not initialize libevent! ");  
    52.           return 1;  
    53.       }  
    54.     
    55.       //创建并绑定一个event  
    56.       struct event *listen_event;  
    57.       listen_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept_cb, (void*)base);  
    58.       event_add(listen_event, NULL);//注册时间,参数NULL表示无超时设置  
    59.       event_base_dispatch(base);//)程序进入无限循环,等待就绪事件并执行事件处理  
    60.     
    61.       printf("The End.");  
    62.       return 0;  
    63.   }  
    64.     
    65.   void do_accept_cb(evutil_socket_t listener, short event, void *arg)  
    66.   {  
    67.       struct event_base *base = (struct event_base *)arg;  
    68.       evutil_socket_t fd;  
    69.       struct sockaddr_in sin;  
    70.       socklen_t slen;  
    71.       fd = accept(listener, (struct sockaddr *)&sin, &slen);  
    72.       if (fd < 0) {  
    73.           perror("accept");  
    74.           return;  
    75.       }  
    76.     
    77.       printf("accept: fd = %u ", fd);  
    78.     
    79.       //使用bufferevent_socket_new创建一个struct bufferevent *bev,关联该sockfd,托管给event_base  
    80.       struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);//BEV_OPT_CLOSE_ON_FREE表示释放buff  
    81.   erevent时关闭底层传输端口。这将关闭底层套接字,释放底层bufferevent等。  
    82.     
    83.       bufferevent_setcb(bev, read_cb, NULL, error_cb, arg);  
    84.       bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST);//启用read/write事件  
    85.   }  
    86.     
    87.   void read_cb(struct bufferevent *bev, void *arg)  
    88.   {  
    89.   #define MAX_LINE    256  
    90.       char line[MAX_LINE+1];  
    91.       int n;  
    92.       evutil_socket_t fd = bufferevent_getfd(bev);  
    93.     
    94.       while (n = bufferevent_read(bev, line, MAX_LINE), n > 0) {  
    95.           line[n] = '';  
    96.           printf("fd=%u, read line: %s ", fd, line);  
    97.     
    98.           bufferevent_write(bev, line, n);  
    99.       }  
    100.   }  
    101.     
    102.   void write_cb(struct bufferevent *bev, void *arg) {}  
    103.     
    104.   void error_cb(struct bufferevent *bev, short event, void *arg)  
    105.   {  
    106.       evutil_socket_t fd = bufferevent_getfd(bev);  
    107.       printf("fd = %u, ", fd);  
    108.       if (event & BEV_EVENT_TIMEOUT) {  
    109.           printf("Timed out "); //if bufferevent_set_timeouts() called  
    110.       }  
    111.       else if (event & BEV_EVENT_EOF) {  
    112.           printf("connection closed ");  
    113.       }  
    114.       else if (event & BEV_EVENT_ERROR) {  
    115.           printf("some other error ");  
    116.       }  
    117.       bufferevent_free(bev);  
    118.   }  

    编译:

    gcc -I/usr/include -o 123 libevent_server.c -L/usr/local/lib -levent

    注意这里应该是包含文件的路径和库文件的路径加上去,具体路径取决于安装目录

    测试1:将客户端的并发数设置为2,查看运行结果

    服务端:

    客户端:

    测试2:将客户端的并发数设置为10000,(如果没有修改内核,需要修改句柄的最大数,ulimit n 65535)查看端口占用结果:

    lsof i:8000 >log

    grep “TCP localhost.localdomain” log |wc l 查看端口占用20001,结果正确,测试成功。


    转载出处:http://blog.csdn.net/feitianxuxue

  • 相关阅读:
    在Spring Bean的生命周期中各方法的执行顺序
    java面试宝典
    js代码中实现页面跳转的几种方式
    APP测试学习:系统资源分析
    APP测试学习:webview性能分析
    APP测试学习:app启动性能分析
    App测试学习:自动遍历测试
    性能测试学习:jmeter通过代理录制、回放请求
    Docker学习五:如何搭建私有仓库
    Docker学习四:容器基本操作
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318289.html
Copyright © 2020-2023  润新知