使用libevent跨平台事件驱动库进行网络编程(转)
libevent是一个事件触发的网络库,支持Linux, BSD, Mac OS X, Solaris 和Windows。如果你将要开发的应用程序需要支持多平台,那么建议你采用这个库,即使你的应用程序只需要支持一个平台,选择libevent也是有好处的,因为它可以根据编译/运行环境切换底层的事件驱动机制,这既能充分发挥系统的性能,又增加了软件的可移植性。
它封装并且隔离了事件驱动的底层机制,除了一般的文件描述符读写操作外,它还提供有读写超时、定时器和信号回调,另外,它还允许为事件设定不同的优先级,当前版本(1.3)的libevent还提供dns和http协议的异步封装,这一切都让这个库尤其适合于事件驱动应用程序的开发。
参考链接:
[1] Network Programming Using Libevent - (I)
[2] Network Programming Using Libevent - (II)
[3] Network Programming Using Libevent - (III)
[4] http://unx.ca/log/category/libevent/
[5] http://tb.blog.csdn.net/TrackBack.aspx?PostId=1808095
通常我们在建立服务器的处理模型的时候,主要是下面集中模型;
(1) 一个新的Connection 进来,用 fork() 产生一个 Process 处理。
(2) 一个新的Connection 进来,用 pthread_create() 产生一个 Thread 处理。
(3) 一个新的Connection 进来,丢入 Event-based Array,由 Main Process 以 Nonblocking 的方式处理所有的 I/O。
(2) 一个新的Connection 进来,用 pthread_create() 产生一个 Thread 处理。
(3) 一个新的Connection 进来,丢入 Event-based Array,由 Main Process 以 Nonblocking 的方式处理所有的 I/O。
这三种方法当然有各自的缺点:
(1) 用 fork() 的问题在于每一个 Connection 进来时的成本太高,如果同时接入的并发连接数太多容易进程数量很多,进程之间的切换开销会很大,同时对于老的内核(Linux)会产生雪崩效应。
(2) 用 Multi-thread 的问题在于 Thread-safe 与 Deadlock 问题难以解决,另外有 Memory-leak 的问题要处理,这个问题对于很多程序员来说无异于恶梦,尤其是对于连续服务器的服务器程序更是不可以接受。
(1) 用 fork() 的问题在于每一个 Connection 进来时的成本太高,如果同时接入的并发连接数太多容易进程数量很多,进程之间的切换开销会很大,同时对于老的内核(Linux)会产生雪崩效应。
(2) 用 Multi-thread 的问题在于 Thread-safe 与 Deadlock 问题难以解决,另外有 Memory-leak 的问题要处理,这个问题对于很多程序员来说无异于恶梦,尤其是对于连续服务器的服务器程序更是不可以接受。
(3) 用 Event-based 的方式在于不好实现,尤其是要注意到事件产生时必须无阻塞 Nonblocking,于是会需要实现缓存 Buffering 的问题,而 Multi-thread 所会遇到的 Memory-leak 问题在这边会更严重。而在多 CPU 的系统上没有办法使用到所有的 CPU 资源。
针对上面存在的问题,通常采用的方法有:
(1) 以 Poll 池的方式解决:当一个 Process 处理完一个 Connection 后,不直接死掉,而继续回到 accept() 的状态继续处理,但这样会遇到 Memory-leak 的问题,于是采用这种方式的人通常会再加上「处理过 N 个 Connection 后死掉,由 Parent Process 再 fork() 一只新的」。最有名的例子是 Apache 1.3服务器,大家可以参考其源代码的实现。
(2) thread-safe 的问题可以寻找其他 Thread-safe Library 直接使用。Memory-leak 的问题可以试着透过 Garbage Collection Library 分析出来。Apache 2.0 的 Thread MPM 就是使用这个模式。
然而,目前高效率的 Server 都偏好采用 Event-based,一方面是没有 Create Process/Thread 所造成的 Overhead,另外一方面是不需要透过 Shared Memory 或是 Mutex 在不同的 Process/Thread 之间交换资料。
Event-based 在实现上的几个复杂的地方在于:
◆ select() 与 poll() 的效率过慢,造成每次要判断「有哪些 Event 发生」这件事情的成本很高,这在 BSD 支援 kqueue()、Linux 支援 epoll()、Solaris 支援 /dev/poll 后就解决了,在Windows平台上通过完成端口的方式解决了.但这两组 Function 都不是 Standard,于是在不同的平台上就必须再改一次。
◆ 对于非阻塞的IO模型, 因为 Nonblocking,所以在 write() 或是 send() 时满了需要自己 Buffering。
◆ 因为 Nonblocking,所以不能使用 fgets() 或是其他类似的 function,于是需要自己刻一个 Nonblocking 的 fgets()。但是使用者所丢过来的资料又不能保证在一次 read() 或 recv() 就有一行,于是要自己做 Buffering。
实际上这三件事情在 libevent 都有 Library 处理掉了.
浙公网安备 33010602011771号