libevent分析和使用

1.libevent介绍

libevent是一个轻量级的基于事件驱动的高性能的开源网络库,支持多种系统,对不同系统的函数进行再次封装统一接口,编译的时候,选择自己的系统就行了

因为libevent的出色的轻量级、高性能的表现,很多其他的开源库基于此库,开发出了适应更多场景的开源库 

例如memcached,在libevent上面增加了多线程的支持,主要利用了主线程+多个工作线程,实现线程池管理线程

2.libevent实现原理

libevent主要是用来处理大量连接的,处理多个连接的时候,一般都会用到IO多路复用+多线程/多进程

  • IO多路复用:监测多个连接,当有某个就绪,就进行相应的处理,整个处理过程是一个单线程、同步的方式,这样虽然减少了线程切换,节约了系统资源,但是很有可能浪费时间在等待过程中,这个等待时间有可能是在等某个连接数据到来(这个等待无关紧要),也有可能在处理的过程中发生了阻塞(编程上尽量使用非阻塞)
  • 多线程/多进程:每当有一个连接请求,就建立一个线程去处理,就算某个处理线程出现了阻塞,其他线程也会利用cpu资源,多线程是有弊端的,每个线程都需要占用栈空间,当连接过多(DDoS攻击),栈空间消耗很大,线程创建是需要消耗时间的,针对这些问题,使用线程池和keepalive机制,杜绝一些站着茅坑不拉屎的连接

libevent使用的是多路IO复用(select、poll、epoll),利用事件,事件的回调函数

lbevent的事件支持三种,分别是网络IO、定时器和信号。定时器的数据结构使用最小堆(Min Heap),以提高效率。网络IO和信号的数据结构采用了双向链表(TAILQ)。

3.libevent的安装

1.首先去官网或者git上获取源码安装包

2.进入libevent目录,执行./autogen.sh,这个过程可能需要一些第3方工具,一个什么tool,生成.lo文件的工具

3. ./configure && make; make install

4.libevent的使用

1.event_init:创建一个事件队列

2.event_set:事件初始化,创建事件、事件回调函数,传入的event指针参数存在整个事件生命周期,因为是简单的赋值,并不是内存拷贝

3.event_base_set:把事件和事件队列关联起来

4.event_add:添加事件到事件队列,可以设置超时时间,有添加就有删除event_del

5.event_base_dispatch:循环等待事件就绪

上面的这些函数是把多路IO复用函数再次封装得到的,在上层增加了事件管理

5.libevent使用实例

下面这段代码有一点问题,有一段malloc的内存在close(sock_fd)没有free这段内存

#include
#include
#include
#include
#include
#include
#include
#include
#include  

#define SERVER_IP 	"127.0.0.1"
#define SERVER_PORT	6666
#define LISTEN_MAX	5
#define BUF_SIZE 	512

struct event_base *base;

static int init_socket_server(const char* ip, int port)
{
	int on = 1;
	int ret = -1;
	int sock_fd = -1;
	struct sockaddr_in server_addr;
	
	memset(&server_addr, 0, sizeof(server_addr));
	
	sock_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sock_fd)
	{
		printf("socket failed\n");
		exit(1);
	}
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_addr.sin_addr.s_addr = inet_addr(ip);
	
	ret = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	if (-1 == ret)
	{
		printf("setsockopt failed\n");
		exit(1);
	}
	
	ret = bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
	if (-1 == ret)
	{
		printf("bind failed\n");
		exit(1);
	}
	
	ret = listen(sock_fd, LISTEN_MAX);
	if (-1 == ret)
	{
		printf("listen failed\n");
		exit(1);
	}
	
	return sock_fd;
}

static void read_write_process(int sock_fd, short event, void* arg)
{
	printf("write\n");
	int nbyte = 0;
	char buffer[BUF_SIZE];
	
	memset(buffer, 0, sizeof(buffer));
	nbyte = recv(sock_fd, buffer, BUF_SIZE, 0);
	if (0 == nbyte)
	{
		close(sock_fd);
		return;
	}
	nbyte = send(sock_fd, buffer, strlen(buffer)+1, 0);
	printf("nbyte = %d\n", nbyte);
}

static void accept_process(int sock_fd, short event, void* arg)
{
	printf("accept\n");
	int new_fd = -1;
	socklen_t sin_size;
	struct event *event_list;
	struct sockaddr_in client_addr;
	
	event_list = (struct event*)malloc(sizeof(struct event));
	sin_size = sizeof(struct sockaddr_in);
	memset(&client_addr, 0, sizeof(client_addr));
	new_fd = accept(sock_fd, (struct sockaddr*)&client_addr, &sin_size);
	if (-1 == new_fd)
	{
		printf("accept failed\n");
		exit(1);
	}

	event_set(event_list, new_fd, EV_READ|EV_PERSIST, read_write_process, NULL);
	event_base_set(base, event_list);
	event_add(event_list, NULL);


}

int main(int argc, char** argv)
{
	int sock_fd = -1;
	struct event event_list;
	
	sock_fd = init_socket_server(SERVER_IP, SERVER_PORT);
	
	base = event_init();//epoll_create
	event_set(&event_list, sock_fd, EV_READ|EV_PERSIST, accept_process, NULL);
	//设置好事件以及事件的回调函数, EV_PERSIST持续性事件,激活之后不需要重新event_add
	event_base_set(base, &event_list);//base和event_list关联起来
	event_add(&event_list, NULL);//epoll_ctl
	event_base_dispatch(base);//epoll_wait
	
	return 0;
}

 

 

 

你可能感兴趣的:(网络通信)