LIBEVENT 框架

LAMP

从LAMP说起: 是一个缩写,它指一组通常一起使用来运行动态网站或者服务器的自由软件

  • Linux - 操作系统
  • Apache - 网页服务器
  • MySQL - 数据库管理系统(或者数据库服务器)
  • PHP Perl 或 Python - 脚本语言
    在这里插入图片描述
    C10K 问题:并发能力突破不了1万连接

libevent

libevent是一个轻量级的开源的高性能的事件触发的网络库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue等系统调用管理事件机制。
它被众多的开源项目使用,例如大名鼎鼎的memcached等。

特点:

  • 事件驱动,高性能;
  • 轻量级,专注于网络(相对于ACE);
  • 开放源码,代码相当精炼、易读;
  • 跨平台,支持Windows、Linux、BSD和Mac OS;
  • 支持多种I/O多路复用技术(epoll、poll、dev/poll、select和kqueue等),在不同的操作系统下,做了多路复用模型的抽象,可以选择使用不同的模型,通过事件函数提供服务;
  • 支持I/O,定时器和信号等事件;
  • 采用Reactor模式;
    libevent是一个典型的reactor模式的实现。
    普通的函数调用机制:程序调用某个函数,函数执行,程序等待,函数将结果返回给调用程序(如果含有函数返回值的话),也就是顺序执行的。
    Reactor模式的基本流程:应用程序需要提供相应的接口并且注册到reactor反应器上,如果相应的事件发生的话,那么reactor将自动调用相应的注册的接口函数(类似于回调函数)通知你,所以libevent是事件触发的网络库。

在这里插入图片描述

libevent的功能

Libevent提供了事件通知,io缓存事件,定时器,超时,异步解析dns,事件驱动的http server以及一个rpc框架。

  • 事件通知:当文件描述符可读可写时将执行回调函数。
  • IO缓存:缓存事件提供了输入输出缓存,能自动的读入和写入,用户不必直接操作io。
  • 定时器:libevent提供了定时器的机制,能够在一定的时间间隔之后调用回调函数。
  • 信号:触发信号,执行回调。
  • 异步的dns解析:libevent提供了异步解析dns服务器的dns解析函数集。
  • 事件驱动的http服务器:libevent提供了一个简单的,可集成到应用程序中的HTTP服务器。
  • RPC客户端服务器框架:libevent为创建RPC服务器和客户端创建了一个RPC框架,能自动的封装和解封数据结构。

libevent官网

http://libevent.org/

安装步骤

注意:以root用户身份操作
1、下载源码包

wget https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz

2、解压

tar zxvf libevent-2.1.12-stable.tar.gz

3、配置安装路径

cd libevent-2.1.12-stable
./configure --disable-openssl

4、编译并安装

make
make install

5、测试libevent是否安装成功:

 # ls -la /usr/local/include | grep event

在这里插入图片描述
6、如果编译后的程序提示找不到libvent的so,则创建库的链接和缓存文件
ldconfig
编译选项 -levent

Linux下libevent主要API介绍

创建事件集
struct event_base *event_base_new(void);

创建事件
struct event event_new
(struct event_base ,evutil_socket_t ,short ,event_callback_fn, void*)

添加事件
int event_add(struct event * ev,const struct timeval* timeout)

删除事件
int event_del(struct event *)

事件循环
int event_base_loop(struct event_base *base, int flags)
int event_base_dispatch(struct event_base *event_base)

libevent使用步骤

1.创建socket
2.创建事件集event_base
3.创建event(socket, EV_READ, callback1) / event(socket, EV_WRITE, callback2)
4.把event添加到事件集event_base
5.event_base_dispatch(evnet_base); event_base_loop();

注 意:
程序的最后调用event_base_dispatch(base);实现事件的循环处理

while()
{
//调用多路复用
event_base_dispatch(base);
……
}

libevent 编程案例

1.使用libevent 改造epoll 范例

//main.c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h> 
#include <unistd.h>
#include <event.h>
#include <event2/event.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>

#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>

typedef struct _ConnectStat  ConnectStat;

#define BUFLEN  1024

struct _ConnectStat {
   
	struct event*  ev;
	int fd;
	char send_buf[BUFLEN];
	//PF *handler;//不同页面的处理函数	
};

//echo 服务实现相关代码
ConnectStat * stat_init(int fd);
//void accept_connection(int fd, void *data);
void accept_connection(int fd, short events, void* arg);

void do_welcome_handler(int fd, short events, void* arg);
//void do_echo_handler(int fd, void  *data);
void do_echo_handler(int fd, short events, void *arg);

void do_echo_response(int fd, short events, void *arg);

struct event_base * ev_base;


void usage(const char* argv)
{
   
	printf("%s:[ip][port]\n", argv);
}

void set_nonblock(int fd)
{
   
	int fl = fcntl(fd, F_GETFL);
	fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}

int startup(char* _ip, int _port)  //创建一个套接字,绑定,检测服务器
{
   
	//sock
	//1.创建套接字
	int sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0)
	{
   
		perror("sock");
		exit(2);
	}

	int opt = 1;
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	//2.填充本地 sockaddr_in 结构体(设置本地的IP地址和端口)
	struct sockaddr_in local;
	local.sin_port = htons(_port);
	local.sin_family = AF_INET;
	local.sin_addr.s_addr = inet_addr(_ip);

	//3.bind()绑定
	if (bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
	{
   
		perror("bind");
		exit(3);
	}
	//4.listen()监听 检测服务器
	if (listen(sock, 5) < 0)
	{
   
		perror("listen");
		exit(4);
	}
	
	return sock;    //这样的套接字返回
}


ConnectStat * stat_init(int fd) {
   
	ConnectStat * temp = NULL;
	temp = (ConnectStat *)malloc(sizeof(ConnectStat));

	if (!temp) {
   
		fprintf(stderr, "malloc failed. reason: %m\n");
		return NULL;
	}

	memset(temp, '\0', sizeof(ConnectStat));
	temp->fd = fd;
	//temp->status = 0;
}

void do_welcome_handler(int fd, short events, void* arg){
   
	const char * WELCOME= "Welcome.\n";
	int wlen = strlen(WELCOME);
	int n ;
	ConnectStat * stat = (ConnectStat *)(arg);
	
	if( (n = write(fd, "Welcome.\n",wlen)) != wlen ){
   
		
		if(n<=0){
   
		    fprintf(stderr, "write failed[len:%d], reason: %s\n",n,strerror(errno));
		}else fprintf(stderr, "send %d bytes only ,need to send %d bytes.\n",n,wlen);
		
	}else {
   
		//commUpdateReadHandler(fd, do_echo_handler,(void *)stat);
		event_set(stat->ev, fd, EV_READ, do_echo_handler, (void *)stat);
		stat->ev->ev_base = ev_base;//必须重置事件集合
		event_add(stat->ev, NULL);
		
	}
}


void do_echo_handler(int fd, short events, void *arg) {
   
	ConnectStat * stat = (ConnectStat *)(arg);
	char * p = NULL;
	
	assert(stat!=NULL);
	
	
	p = stat->send_buf;
	*p++ = '-';
	*p++ = '>';
	ssize_t _s = read(fd, p, BUFLEN-(p-stat->send_buf)-1); //2字节"->" +字符结束符.
    if (_s > 0)
    {
   
		
		*(p+_s) = '\0';
		printf("receive from client: %s\n", p);
		//_s--;
		//while( _s>=0 && ( stat->send_buf[_s]=='\r' || stat->send_buf[_s]=='\n' ) ) stat->send_buf[_s]='\0';
		
		if(!strncasecmp(p, "quit", 4)){
   //退出.
			//comm_close(fd);
			event_free<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏过山河,踏过海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值