libevent 的使用

      libevent 封装了低层最高效的网络模型,windows的compIO,linux下的epoll模型,freebsd的kqueue,提供统一的异步调用接口; 以事件方式驱动,chrome,memcached 都在使用该框架.

      libevent 同时也支持DNS,HTTP协议和RPC调用框架

一. 定时器

#include <stdio.h>
#include <event.h>

void onTime(int sock,short event,void *arg)
{
	printf("Game over!\n");

	struct timeval tv;
	tv.tv_sec = 1;
	tv.tv_usec = 0;

	// 事件执行后,默认就被删除,需要重新add,使之重复执行
	event_add((struct event*)arg,&tv);
}

int main()
{
	// 初始化事件
	event_init();

	// 设置定时器回调函数
	struct event evTime;
	evtimer_set(&evTime,onTime,&evTime);

	struct timeval tv;  // 1s后执行
	tv.tv_sec = 1;
	tv.tv_usec = 0;
	
        // 添加事件
	event_add(&evTime,&tv);
	// 循环派发事件
	event_dispatch();

	return 0;
}

    编译: gcc -o  time_test time_test.c -I/usr/local/libevent/include -L/usr/local/libevent/lib -levent

二. TCP服务器

    

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <event.h>


struct event_base *base;

// 读事件
void onRead(int clifd,short ievent,void *arg)
{
	int ilen;
	char buf[1500];

	ilen = recv(clifd,buf,1500,0);

	if(ilen <= 0)
	{
		printf("Client close\n");
		
		struct event *pread = (struct event*)arg;
		event_del(pread);
		delete pread;

		close(clifd);
		return;
	}
	
	buf[ilen] = '\0';
	printf("Accpet: %s\n",buf);
}

// 连接事件
void onAccept(int svrfd,short ievent,void *arg)
{
	int clifd;
	struct sockaddr_in cliaddr;

	socklen_t sinsize = sizeof(cliaddr);
	clifd = accept(svrfd,(struct sockaddr*)&cliaddr,&sinsize);

	struct event *pread = new event;
	event_set(pread,clifd,EV_READ|EV_PERSIST,onRead,pread);  // 注册读(写)事件
	event_base_set(base,pread);
	event_add(pread,NULL);
}


int main()
{
	int svrfd;
	struct sockaddr_in svraddr;

	memset(&svrfd,0,sizeof(svraddr));
	svraddr.sin_family = AF_INET;
	svraddr.sin_port = htons(1234);
	svraddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	svrfd = socket(AF_INET,SOCK_STREAM,0);
	bind(svrfd,(struct sockaddr*)&svraddr,sizeof(svraddr));

	listen(svrfd,10);

	// 初始化事件库
	base = event_base_new();

	// 初始化一个连接事件,EV_PRESIST指定重复执行该事件
	struct event evlisten;
	event_set(&evlisten,svrfd,EV_READ|EV_PERSIST,onAccept,NULL);

	// 设置为base事件
	event_base_set(base,&evlisten);
	// 添加事件
	event_add(&evlisten,NULL);
	// 事件循环
	event_base_dispatch(base);

	return 0;

}

    要实现windows下更高效的IOCP方式的API,IOCP在准备好读写事件时不会通知你的程序去拷贝数据,而时在数据完成从内核态拷贝到用户态时才通知应用程序. libevent 2提供了 bufferevent 接口,支持这种编程范式 

三. HTTP服务器

   

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <event.h>
#include <evhttp.h>

void reqHandler(struct evhttp_request *req,void *arg)
{
	struct evbuffer *buf = evbuffer_new();
	
	// 发送响应
	evbuffer_add_printf(buf, "Thanks for the request");
	evhttp_send_reply(req,HTTP_OK,"Client",buf);
	
	evbuffer_free(buf);
	
	return;
}

int main(int argc,char **argv)
{
	short port = 8000;
	const char *addr = "192.168.1.11";
	struct evhttp *httpserv = NULL;

	event_init();
        // 启动http服务
	httpserv = evhttp_start(addr,port);

	// 设置回调
	evhttp_set_gencb(httpserv, reqHandler,NULL);
	printf("Server started on port %d\n",port);

	event_dispatch();

	return 0;
}

    浏览器访问: http://192.168.1.11:8000 会显示 Thanks for the request

    原文参见: http://blog.csdn.net/yyyiran/article/details/12219737

猜你喜欢

转载自tcspecial.iteye.com/blog/2090435