先来看一个基于定时器的事件驱动
#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 有说道,看起来还行。。不过我们最终的生产环境还是没有用第三方库,自己写了事件驱动。。真是造轮子。。
自己造轮子如果造得圆还好了…… 我比较受不了放着开源的不用自己造轮子,造出来还是方的……