精华内容
下载资源
问答
  • libev === First let's talk about libev, it is a lib used in ss. The coding style of libev is ugly. ...libevent ====   转载于:https://www.cnblogs.com/sansna/p/9814288.html

    libev

    ===

    First let's talk about libev, it is a lib used in ss.

    The coding style of libev is ugly.

    To see man page of libev by: man ./ev.3

    3 files need to take care when understanding the implementation of the libev: ev.c, ev_epoll.c, ev_vars.h.

    ev_vars.h defines the most members inside the struct ev_loop, which is the central structure of the lib.

    In linux's epoll implementation of the libev, fds are added to the ev_io var by ev_io_init(); and then this event is added to the main *loop global variable, which is the EV_A through ev_io_start(); The main epoll_ctl and epoll_wait behavior runs in ev_run();

    What happens in ev_run()? It triggers the .backend_poll() which is assigned during initialization in loop_init() when we do EV_P = EV_DEFAULT. And if it is linux, the epoll_poll() is used.

    In epoll_poll(), the backend_fd is epoll_wait()-ed, number of observed fds is returned, and all the observed fds are iterated. If observed ops do not match the ops that we want, the epoll_ctl() is called with MOD/DEL accordingly. then fd_event() ->fd_event_nocheck()->ev_feed_event() is called. In the ev_feed_event() function, the ev_io *ptr of the fds and the observed revent (EV_READ/EV_WRITE) is pushed into a pending list of global loop->pendings, with priority as its 2-dim array index and returned to ev_run() main loop, the last step of the main loop is the EV_INVOKE_PENDING, which is to invoke the registered cb function to the fd with priority ordered.

    libevent

    ====

     

    转载于:https://www.cnblogs.com/sansna/p/9814288.html

    展开全文
  • 方案库 鸭库scheme-lib是一个计划使用的库。目前支持android osx linux windows,其他平台在规划中。 官方主页: ://evilbinary.github.io/scheme-lib/ QQ群:Lisp兴趣小组239401374 安装编译 Linux ...
  • 最近在做websocket porting的工作中,需要实现最底层socket读和写,基于同步读,libevent, libuv和android Looper都写了一套,从中体会不少。 1)同步阻塞读写 最开始采用同步阻塞读写,主要是为了快速实现来...
    展开全文
  • 基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET 基于libevent, libuv和android Looper不断演进socket编程 分类: 移动云 2013-05-24 17:33 2422人阅读 评论(2) ...

    基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET

    基于libevent, libuv和android Looper不断演进socket编程

    分类: 移动云 2422人阅读 评论(2) 收藏 举报

    最近在做websocket  porting的工作中,需要实现最底层socket读和写,基于同步读,libevent, libuv和android Looper都写了一套,从中体会不少。

    1)同步阻塞读写

    最开始采用同步阻塞读写,主要是为了快速实现来验证上层websocket协议的完备性。优点仅仅是实现起来简单,缺点就是效率不高,不能很好利用线程的资源,建立连接这一块方法都是类似的,主要的区别是在如何读写数据,先看几种方法共用的一块:

     

    1. int n = 0;  
    2. struct sockaddr_in serv_addr;  
    3. event_init();  
    4. if((mSockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){  
    5.     //TODO error  
    6.     return;  
    7. }  
    8. memset(&serv_addr, '0'sizeof(serv_addr));  
    9. serv_addr.sin_family = AF_INET;  
    10. serv_addr.sin_port = htons(url.port());  
    11. if(inet_pton(AF_INET, url.host().utf8().data(), &serv_addr.sin_addr)<=0){  
    12.     return;  
    13. }  
    14. if( connect(mSockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){  
    15.     return;  
    16. }  
        int n = 0;
        struct sockaddr_in serv_addr;
        event_init();
        if((mSockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
            //TODO error
            return;
        }
        memset(&serv_addr, '0', sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(url.port());
        if(inet_pton(AF_INET, url.host().utf8().data(), &serv_addr.sin_addr)<=0){
            return;
        }
        if( connect(mSockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
            return;
        }

    这里由于是client,所以比较简单,当然缺失了DNS解析这一块。然后,就是要监视读数据,由于是同步阻塞读,所以需要在循环里不断地去read/recv:

     

     

    1. while (1) {  
    2.     ssize_t result = recv(fd, buf, sizeof(buf), 0);  
    3.     if (result == 0) {  
    4.         break;  
    5.     } else if (result < 0) {  
    6.         perror("recv");  
    7.         close(fd);  
    8.         return 1;  
    9.     }  
    10.     fwrite(buf, 1, result, stdout);  
    11. }  
        while (1) {
            ssize_t result = recv(fd, buf, sizeof(buf), 0);
            if (result == 0) {
                break;
            } else if (result < 0) {
                perror("recv");
                close(fd);
                return 1;
            }
            fwrite(buf, 1, result, stdout);
        }

    缺点就显而易见,此线程需要不断轮询。当然,这里是个例子程序,正式代码中不会处理这么草率。

     

    2)libevent

    对上面的改进方法就是基于异步非阻塞的方式来处理读数据,在linux上一般是通过epoll来做异步事件侦听,而libevent是一个封装了epoll或其他平台上异步事件的c库,所以基于libevent来做异步非阻塞读写会更简单,也能跨平台。重构的第一个步是设置socketFD为非阻塞:

     

    1. static int setnonblock(int fd)  
    2. {  
    3.     int flags;  
    4.     flags = fcntl(fd, F_GETFL);  
    5.     if (flags < 0){  
    6.         return flags;  
    7.     }  
    8.     flags |= O_NONBLOCK;  
    9.     if (fcntl(fd, F_SETFL, flags) < 0){  
    10.         return -1;  
    11.     }  
    12.     return 0;  
    13. }  
    static int setnonblock(int fd)
    {
        int flags;
        flags = fcntl(fd, F_GETFL);
        if (flags < 0){
            return flags;
        }
        flags |= O_NONBLOCK;
        if (fcntl(fd, F_SETFL, flags) < 0){
            return -1;
        }
        return 0;
    }

    然后需要在单独的线程中维护event loop,并添加read事件侦听:

     

     

    1. static void* loopListen(void *arg)  
    2. {  
    3.     SocketStreamHandle *handle = (SocketStreamHandle *)arg;  
    4.     struct event_base* base = event_base_new();  
    5.     struct event ev_read;  
    6.     handle->setReadEvent(&ev_read);  
    7.     setnonblock(handle->getSocketFD());  
    8.     event_set(&ev_read, handle->getSocketFD(), EV_READ|EV_PERSIST, onRead, handle);  
    9.     event_base_set(base, &ev_read);  
    10.     event_add(&ev_read, NULL);  
    11.     event_base_dispatch(base);  
    12. }  
    static void* loopListen(void *arg)
    {
        SocketStreamHandle *handle = (SocketStreamHandle *)arg;
        struct event_base* base = event_base_new();
        struct event ev_read;
        handle->setReadEvent(&ev_read);
        setnonblock(handle->getSocketFD());
        event_set(&ev_read, handle->getSocketFD(), EV_READ|EV_PERSIST, onRead, handle);
        event_base_set(base, &ev_read);
        event_add(&ev_read, NULL);
        event_base_dispatch(base);
    }
    1.     pthread_t pid;  
    2.     pthread_create(&pid, 0, loopListen, this);  
        pthread_t pid;
        pthread_create(&pid, 0, loopListen, this);
    

    然后在onRead方法中处理数据读取:

     

    1. static void onRead(int fd, short ev, void *arg)  
    2. {  
    3.     while(true){  
    4.         char *buf = new char[1024];  
    5.         memset(buf, 0, 1024);  
    6.         int len = read(fd, buf, 1024);  
    7.         SocketStreamHandle *handle = (SocketStreamHandle *)arg;  
    8.         if(len > 0){  
    9.             SocketContext *context = new SocketContext;  
    10.             context->buf = buf;  
    11.             context->readLen = len;  
    12.             context->handle = handle;  
    13.             WTF::callOnMainThread(onReadMainThread, context);  
    14.             if(len == 1024){  
    15.                 continue;  
    16.             }else{  
    17.                 break;  
    18.             }  
    19.         }else{  
    20.             if(errno == EAGAIN || errno == EWOULDBLOCK){  
    21.                 return;  
    22.             }else if(errno == EINTR){  
    23.                 continue;  
    24.             }  
    25.             __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "onCloseMainThread, len:%d, errno:%d", len, errno);  
    26.             WTF::callOnMainThread(onCloseMainThread, handle);  
    27.             event_del(handle->getReadEvent());  
    28.         }  
    29.     }  
    30. }  
    static void onRead(int fd, short ev, void *arg)
    {
        while(true){
            char *buf = new char[1024];
            memset(buf, 0, 1024);
            int len = read(fd, buf, 1024);
            SocketStreamHandle *handle = (SocketStreamHandle *)arg;
            if(len > 0){
                SocketContext *context = new SocketContext;
                context->buf = buf;
                context->readLen = len;
                context->handle = handle;
                WTF::callOnMainThread(onReadMainThread, context);
                if(len == 1024){
                    continue;
                }else{
                    break;
                }
            }else{
                if(errno == EAGAIN || errno == EWOULDBLOCK){
                    return;
                }else if(errno == EINTR){
                    continue;
                }
                __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "onCloseMainThread, len:%d, errno:%d", len, errno);
                WTF::callOnMainThread(onCloseMainThread, handle);
                event_del(handle->getReadEvent());
            }
        }
    }

    这里比较有讲究的是:

     

    1)当一次buf读不完,需要在循环里再次读一次

    2)当read到0时,表示socket被关闭,这时需要删除事件侦听,不然会导致cpu 100%

    3)当read到-1时,不完全是错误情况,比如errno == EAGAIN || errno == EWOULDBLOCK表示暂时不可读,歇一会后面再读。errno == EINTR表示被系统中断,应重读一遍

    4)onRead是被libevent中专门做事件侦听的线程调用的,所以有的时候需要回到主线程,比如: WTF::callOnMainThread(onReadMainThread, context);这里就需要注意多线程间的同步问题。

    3)libuv

    libuv在libevent更进一步,它不但有event loop,并且把socket的各种操作也覆盖了,所以代码会更简洁,比如最开始的创建连接和创建loop:

     

    1. uv_loop_t *loop = uv_default_loop();  
    2. uv_tcp_t client;  
    3. uv_tcp_init(loop, &client);  
    4. struct sockaddr_in req_addr = uv_ip4_addr(url.host().utf8().data(), url.port());  
    5. uv_connect_t *connect_req;  
    6. connect_req->data = this;  
    7. uv_tcp_connect(connect_req, &client, req_addr, on_connect);  
    8. uv_run(loop);  
        uv_loop_t *loop = uv_default_loop();
        uv_tcp_t client;
        uv_tcp_init(loop, &client);
        struct sockaddr_in req_addr = uv_ip4_addr(url.host().utf8().data(), url.port());
        uv_connect_t *connect_req;
        connect_req->data = this;
        uv_tcp_connect(connect_req, &client, req_addr, on_connect);
        uv_run(loop);

    在on_connect中创建对read的监听:

     

     

    1. static void* on_connect(uv_connect_t *req, int status)  
    2. {  
    3.     SocketStreamHandle *handle = (SocketStreamHandle *)arg;  
    4.     uv_read_start(req->handle, alloc_buffer, on_read);  
    5. }  
    static void* on_connect(uv_connect_t *req, int status)
    {
        SocketStreamHandle *handle = (SocketStreamHandle *)arg;
        uv_read_start(req->handle, alloc_buffer, on_read);
    }

    on_read就和前面类似了。所以libuv是最强大的,极大的省略了socket相关的开发。

     

    4)Android Looper

    Android提供一套event loop的机制,并且可以对FD进行监听,所以如果基于Android Looper,就可以省去对第三方lib的依赖。并且Android也是对epoll的封装,既然如此,值得试一试用Android原生的looper来做这块的event looper。socket连接这块和最开始是一样的,关键是在创建looper的地方:

     

    1. static void* loopListen(void *arg)  
    2. {  
    3.     SocketStreamHandle *handle = (SocketStreamHandle *)arg;  
    4.     setnonblock(handle->getSocketFD());  
    5.     Looper *looper = new Looper(true);  
    6.     looper->addFd(handle->getSocketFD(), 0, ALOOPER_EVENT_INPUT, onRead, handle);  
    7.     while(true){  
    8.         if(looper->pollOnce(100) == ALOOPER_POLL_ERROR){  
    9.             __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "ALOOPER_POLL_ERROR");  
    10.             break;  
    11.         }  
    12.     }  
    13. }  
    static void* loopListen(void *arg)
    {
        SocketStreamHandle *handle = (SocketStreamHandle *)arg;
        setnonblock(handle->getSocketFD());
        Looper *looper = new Looper(true);
        looper->addFd(handle->getSocketFD(), 0, ALOOPER_EVENT_INPUT, onRead, handle);
        while(true){
            if(looper->pollOnce(100) == ALOOPER_POLL_ERROR){
                __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "ALOOPER_POLL_ERROR");
                break;
            }
        }
    }

    代码比较简单就不多说,详细使用方法可以查看<utils/Looper.h>的API。

     

    综上所述,如果是在Android上做,可以直接基于原生的Looper,如果需要跨平台可以基于libuv。总之,要避免同步阻塞,因为这样会导致线程设计上的复杂和低效。

    在Java里也有类似的概念,可以参见以前的博文:

     

    从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一)
    从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(二)
    从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(三)

    展开全文
  • libevent, libev, and libuv , libhv提供具有非阻塞IO计时器的事件循环,但具有更简单的api更丰富的协议。 产品特点 跨平台(Linux,Windows,Mac,Solaris) 事件循环(IO,计时器,空闲) ENABLE_IPV6 ...
  • libevent, libev, and libuv , libhv提供具有非阻塞IO计时器的事件循环,但具有更简单的api更丰富的协议。 :sparkles: 特征 跨平台(Linux,Windows,Mac,Solaris) EventLoop(IO,计时器,空闲) TCP ...
  • Libevent、libev、libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library)

    Libevent,libuv,libev,IOCP,asio,muduo,tbnet,epoll/select/poll 是什么?C10K是什么?

    在研究服务端程序并发能力时看到这些词汇,本文简单记录记录,作为日后细看这些东西的的导引。

    1. epoll/select/poll 是IO复用模型

    • 如果一个请求就创建一个进程的话,进程占用资源多,单机负载能力不行,于是就有了一个进程来处理多个请求的方法,也就是IO复用,目前的常用的IO复用模型有三种:select,poll,epoll。
    • poll 和 select 的实现非常类似,本质上的区别就是存放 fd 集合的数据结构不一样。select 在一个进程内可以维持最多 1024 个连接,poll 在此基础上做了加强,可以维持任意数量的连接。
    • epoll是基于内核的反射机制,在有活跃的 socket 时,系统会调用我们提前设置的回调函数。而 poll 和 select 都是遍历(轮训,如果持有较多数量的链接,如一百万个,性能会比较差)。

    2. Libevent,libuv,libev,IOCP,asio,muduo,tbnet都是网络函数库

    • Libevent、libev、libuv三个网络库,都是C语言实现的异步事件库(Asynchronousevent library),异步事件通知机制就是根据发生的事件,调用相应的回调函数进行处理。

    • 对比下三个库:

      • libevent :名气最大,应用最广泛,历史悠久的跨平台事件库;

      • libev :较libevent而言,设计更简练,性能更好,但对Windows支持不够好;

      • libuv :开发node的过程中需要一个跨平台的事件库,他们首选了libev,但又要支持Windows,故重新封装了一套,linux下用libev实现,Windows下用IOCP实现;

    • 康康github上的start感觉感觉他们的影响力 (libuv >> libevent > libev):

      • https://github.com/libevent/libevent
      • https://github.com/enki/libev
      • https://github.com/libuv/libuv
    • 优先级、事件循环、线程安全维度的对比
      在这里插入图片描述

    • 事件种类

    typelibeventlibevlibuv
    IOfdiofs_event
    计时器 (mono clock)timertimertimter
    计时器(wall clock)periodic
    信号signalsignalsignal
    进程控制childprocess
    文件statstatfs_poll
    每次循环都会执行的Idle事件idleidle
    循环block之前执行prepareprepare
    循环blcck之后执行checkcheck
    嵌套loopembed
    forkfork
    loop销毁之前的清理工作cleanup
    操作另一个线程中的loopasyncasync
    stream ( tcp, pipe, tty )stream ( tcp, pipe, tty )stream ( tcp, pipe, tty )stream ( tcp, pipe, tty )

    这个对比对于libev和libuv更有意义,对于libevent,很多都是跟其设计思想有关的。 libev中的embed很少用,libuv没有也没关系;cleanup完全可以用libuv中的async_exit来替代;libuv没有fork事件。

    • 可移植性:

      • 三个库都支持Linux, *BSD, Mac OS X, Solaris, Windows
      • 对于Unix/Linux平台,没有什么大不同,优先选择epoll,对于windows,libevent、libev都使用select检测和分发事件(不I/O),libuv在windows下使用IOCP。libevent有一个socket handle, 在windows上使用IOCP进行读写。libev没有类似的。但是libevent的IOCP支持也不是很好(性能不高)。所以如果是在windows平台下,使用原生的IOCP进行I/O,或者使用libuv。
    • IOCP是windows下IO事件处理的最高效的一种方式,结合OVERLAPPED IO可以实现真正的完全异步IO。不支持跨平台。

    • boost::asio,C++语言跨平台。用bind做回调也并不比虚函数好,看上去灵活了,代价却更高了。不光是运行时的内存和时间代价,编译时间也更长。基于ASIO开发应用,要求程序员熟悉函数对象,函数指针,熟悉boost库中的boost::bind,内存管理控制方面。

    • asio是一个高性能的网络开发库,Windows下使用IOCP,Linux下使用epoll。

    • Muduo是一个用纯c++写的库,仅在linux下使用,one loop per thread的思想贯穿其中,将I/O 定时 信号都通过文件描述符的方式融合在一起,三类事件等同于一类事件来看待。

    • 有文章对比说muduo比libevent2吞吐量高不少。

    • tbnet是淘宝开源的网络通讯库,底层是epoll和EventLoop。


    参考文献:
    [1] Libevent文档
    [2] select、poll、epoll之间的区别
    [3] libevent、libev、libuv、IOCP、asio、muduo优劣分析、QT下编译libevent静态库
    [4] 一次读懂 Select、Poll、Epoll IO复用技术
    [5] muduo 与 libevent2 吞吐量对比

    展开全文
  • libhv libev libuv libevent 2020-08-28 最新源代码。这是几个经典的跨平台网络开发库
  • Libevent、libev、libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library)。 异步事件库本质上是提供异步事件通知(Asynchronous Event Notification,AEN)的。异步事件通知机制就是根据发生的...
  • 网络库libevent、libev、libuv对比

    万次阅读 多人点赞 2017-05-05 16:42:34
    Libevent、libev、libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library)。 异步事件库本质上是提供异步事件通知(Asynchronous Event Notification,AEN)的。异步事件通知机制就是根据发生的...
  • 简介像libevent,libev和libuv一样,libhv提供具有非阻塞IO计时器的事件循环,但具有更简单的api更丰富的协议。 跨平台(Linux,Windows,Mac,Solaris)事件循环(IO,tim简介)与libevent,libev和libuv一样,...
  • 看到很多技术牛人写的文章,受益匪浅,也很羡慕,羡慕他们的技术还有文采。...欲使用开源网络库libevent、libev、libuv、IOCP、asio、muduo中的一个,经过对比分析,因本服务器系统目前于windows下运行,考虑...
  • [python异步] Linux 异步网络库libevent、libev、libuv对比一、概念:事件、事件循环二、对比三个库:三、在github上的影响力:四、事件种类五、可移植性六、异步架构程序设计原则 一、概念:事件、事件循环 ...
  • libevent/libev/libuv/redisev比较

    千次阅读 2016-04-27 10:38:03
    待续
  • 最近项目需要选型,把所有的平台都撸了一遍,感觉还是libevent比较爽,娇小完备撸完了还不累!
  • Libuv

    2020-11-30 14:27:35
    Libevent、libev、libuv三个网络库,都是c语言实现的异步事件库 libevent :名气最大,应用最广泛,历史悠久的跨平台事件库; libev :较libevent而言,设计更简练,性能更好,但对Windows支持不够好; libuv :开发...
  • 首先排除preactor模式的(难写),即asioACE;其次,尽量选用多进程单线程(简单可横向扩展)的,可以参考nginx。 整体感觉:ACE太庞大,asio 太赶时髦。 ACE太过庞大,使得你即便是只使用它的一小部分,也不得不...
  • libuv libev的对比

    千次阅读 2016-06-28 13:36:03
    libuv libev ,两个名字相当相近的 I/O Library,最近有幸用两个 Library 都写了一些东西,下面就来说一说我本人对两者共同与不同点的主观表述。 高性能网络编程这个话题已经被讨论烂了。异步,异步,还是异步...
  • 库-libuv libev的对比

    千次阅读 2015-11-10 12:02:06
    libuv  libev ,两个名字相当相近的 I/O Library,最近有幸用两个 Library 都写了一些东西,下面就来说一说我本人对两者共同与不同点的主观表述。 高性能网络编程这个话题已经被讨论烂了。异步,异步,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,036
精华内容 814
关键字:

libeventlibuv和