先来看一个基于定时器的事件驱动
#include <stdio.h> #include <event.h> void onTime(int sock, short event, void* arg) { printf("hi there\n"); struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; event_add((struct event*)arg, &tv); } int main() { event_init(); struct event evTime; evtimer_set(&evTime, onTime, &evTime); struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; event_add(&evTime, &tv); event_dispatch(); return 0; }
可以看到流程还是比较清晰简单的,下面再看一个 socket 事件的回调
#include <stdio.h> #include <assert.h> #include <event.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> struct event_base* base; void onRead(int iCliFd, short iEvent, void* arg) { char buf[8192]; int iLen = recv(iCliFd, buf, 8192, 0); if (iLen <= 0) { printf("cli close\n"); struct event* pEvRead = (struct event*)arg; event_del(pEvRead); delete pEvRead; close(iCliFd); return; } buf[iLen] = 0; printf("cli info:\n------------------------\n%s------------------------\n", buf); } void onAccept(int iSvrFd, short iEvent, void* arg) { struct sockaddr_in stCliAddr; socklen_t iSinSize = sizeof(stCliAddr); int iCliFd = accept(iSvrFd, (struct sockaddr*)&stCliAddr, &iSinSize); struct event* pEvRead = new event; event_set(pEvRead, iCliFd, EV_READ|EV_PERSIST, onRead, pEvRead); event_base_set(base, pEvRead); event_add(pEvRead, NULL); } int main() { int iSvrFd = socket(AF_INET, SOCK_STREAM, 0); assert(iSvrFd != -1); struct sockaddr_in stSvrAddr; memset(&stSvrAddr, 0, sizeof(stSvrAddr)); stSvrAddr.sin_family = AF_INET; stSvrAddr.sin_addr.s_addr = INADDR_ANY; stSvrAddr.sin_port = htons(8080); assert(bind(iSvrFd, (struct sockaddr*)&stSvrAddr, sizeof(stSvrAddr)) != -1); assert(listen(iSvrFd, 10) != -1); base = event_base_new(); struct event evListen; event_set(&evListen, iSvrFd, EV_READ|EV_PERSIST, onAccept, NULL); event_base_set(base, &evListen); event_add(&evListen, NULL); event_base_dispatch(base); return 0; }
附上 Makefile
INC += -I/home/adenzhang/tools/libevent-2.0.21-stable/include/ LIB += -L/home/adenzhang/tools/libevent-2.0.21-stable/lib/ -levent all: g++ -g -Wall -o libevent_time_echo libevent_time_echo.cpp $(INC) $(LIB) g++ -g -Wall -o libevent_tcp_echo libevent_tcp_echo.cpp $(INC) $(LIB)
一开始编译的时候报 event_base_new 函数没有实现,后来才发现是机器上的库的版本太老,使用这个命令可以看到链接时使用的具体文件
gcc -print-file-name=libevent.so
下载一个 2.x 的库就可以了,安装也就是 ./configure && make && make install 三部曲,挺顺利没有遇到问题
对于 libevent 的基本理解可以看到这里,http://www.cnblogs.com/cnspace…,详细的源码分析看到这里,http://blog.csdn.net/sparklian…
其实可以看到,libevent 在写 socket 上,跟 epoll 的感觉还是差不多的,而实际上 libevent 在 linux 上也是基于 epoll 的,那么其实可以直接用 epoll,如果在不考虑可移植性的情况下。
Node.js 的 libuv 比 libevent/libev 好用
node js 那么潮爆的东西,还是自己的 weekend 项目用用就算了,在生产环境还是别想了,为了稳定,保守到什么程度,看着 c++11 和 boost 的智能指针封装好了干着急不能用,想要 RAII?自己写封装。代码写起来累点苦力点没关系,甚至运行效率低点也可以堆机器,但是服务器上跑了六七年的代码改一下都要很小心,引入新的第三方库都要评估,何况换语言。。
不是用 Node.js 啊,是用 libuv 啊~设计的很不错的库~
而且源码量也不大,自己大概浏览一遍就有安全感了 : )
搜了一下看到云风的 blog 有说道,看起来还行。。不过我们最终的生产环境还是没有用第三方库,自己写了事件驱动。。真是造轮子。。
自己造轮子如果造得圆还好了…… 我比较受不了放着开源的不用自己造轮子,造出来还是方的……