# libevent
**Repository Path**: andrewgithub/libevent
## Basic Information
- **Project Name**: libevent
- **Description**: libevent study
- **Primary Language**: C
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-10-08
- **Last Updated**: 2022-05-24
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# `Libevent` 简介
`Libevent`是一款事件驱动的网络开发包,由于采用`C`语言开发体积小巧,跨平台,速度极快。大量开源项目使用了`Libevent`比如谷歌的浏览器和分布式的高速缓存系统`memcached`。`libevent`支持`kqueue`,`select`,`poll`,`epoll`,`iocp`。内部事件机制完全独立于公开事件`API`,`libevent`支持跨平台可以在`Linux`,`*BSD`,`MacOSX`,`Solaris`,`Windows`等平台上编译。
**学习条件**:具有一定的`C/C++`基础,熟悉`Linux`
## 环境搭建
- [x] 配置`zlib`库
```bash
# 1. 解压zlib 1.2.11
tar xvf zlib-1.2.11.tar.gz
# 2. 编译
cd zlib-1.2.11/
./configure
make
make install
```
- [x] 配置`openssl`库
```bash
# 1. 解压openssl-1.1.1.tar.gz
tar xvf openssl-1.1.1.tar.gz
# 2. 编译
cd openssl-1.1.1/
./configure
make
make install
```
- [x] 配置`libevent`环境
```bash
# 1.加压liebevent 2.1.8
unzip libevent-master.zip
# 2. 编译
cd libevent-master/
./autogen.sh
./configure
make
make install
# 3.将动态路来连接到 /usr/lib 下或者执行以下 ldconfig
sudo ln -s /usr/local/lib/libevent-2.2.so.1 /usr/lib/libevent-2.2.so.1
```
## 实战实例
### 创建`event_base`
仅仅实现创建上下文
```c
/***
* 创建event base
* */
#include
#include
using namespace std;
int main()
{
std::cout << "test libevent!\n";
//创建libevent的上下文
event_base * base = event_base_new();
if (base)
{
cout << "event_base_new success!" << endl;
}
return 0;
}
```
### 创建`test_server`
`test_server`中说明了如何使用`libevent`创建一个`socket`监听
`evconnlistener_new_bind`一个接口完成了`socket`的创建,绑定和监听。
```c
/***
* 创建event base
* */
#include
#include
#include
#include
#include
#include "event_interface.h"
using namespace std;
/**
A callback that we invoke when a listener has a new connection.
@param listener The evconnlistener
@param fd The new file descriptor
@param addr The source address of the connection
@param socklen The length of addr
@param user_arg the pointer passed to evconnlistener_new()
*/
void listen_cb(struct evconnlistener * evConnListener, evutil_socket_t evUtilSockFd, struct sockaddr * sockAddr, int socklen, void *data)
{
cout << "listen cb is called" << endl;
}
int main(int argc, char *argv[])
{
//1. 忽略管道信号,发送数据给已关闭的socket
//一些socket程序莫名宕掉的原因
if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
{
cout << "ignal pipe signal" << endl;
}
std::cout << "test libevent!\n";
//创建libevent的上下文
event_base * base = event_base_new();
if (!base)
{
cout << "event_base_new failed." << endl;
return -1;
}
else
{
cout << "event_base_new success!" << endl;
}
//监听端口
//socket, bind, listen
sockaddr_in sockIn;
memset(&sockIn, 0, sizeof(sockIn));
sockIn.sin_family = AF_INET;
sockIn.sin_port = htons(SERVER_PORT);
/* 地址没有指定因为对sockIn进行了了memset,地址赋值为0代表着可以为任意可以用的地址 */
struct evconnlistener *pEvListener = evconnlistener_new_bind(base, /* libevent的上下文 */
listen_cb, /* 接收到连接的回调 */
base, /* 回调函数参数 */
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, /* 地址重用,evconnlistenner关闭同时关闭socket */
10, /* 连接队列的大小,对应的listen函数 */
(sockaddr *)&sockIn, /* 绑定地址和端口 */
sizeof(sockIn)
);
//事件分发处理
if(base)
event_base_dispatch(base);
if(pEvListener)
evconnlistener_free(pEvListener);
if(base)
event_base_free(base);
return 0;
}
```
### 创建`test_conf`
`test_conf`主要是实现了,测试当前系统中支持的方法类型和事件特征的支持情况。
```bash
support methods
epoll
poll
select
EV_FEATURE_ET events are supported.
EV_FEATURE_O1 events are supported.
EV_FEATURE_FDS events are not supports.
EV_FEATURE_EARLY_CLOSE events are supported.
event base new with config sucess
```
```c
#include
#include
#include
#include
#include
#include
#include "event_interface.h"
using namespace std;
int main()
{
//忽略管道信号,发送数据给已关闭的socket
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
//创建配置上下文
event_config *config = event_config_new();
//显示支持的网络模式
const char **methods = event_get_supported_methods();
cout << "support methods " << endl;
for(int i = 0; methods[i] != NULL; i++)
{
cout << methods[i] << endl;
}
//设置特征,确认特征时候生效
//这个features在linux中设置没有效果,因为linux中本来就是支持ET模式的,边缘触发模式
// 设置了EV_FEATURE_FDS其他特征嗯就无法设置
//也就是所支持了EV_FEATURE_FDS 其他的特征都是无法支持的
int ret =
event_config_require_features(config, EV_FEATURE_ET|EV_FEATURE_EARLY_CLOSE);
if(OK != ret)
{
cerr << "event config require features failed." << endl;
return ERROR;
}
//初始化libevent上下文
event_base *base = event_base_new_with_config(config);
//config一旦配置好就不需要在使用了
event_config_free(config);
if(!base)
{
cerr << "event base new with config failed!" << endl;
//首次失败就创建一个base取默认值,若是再次失败就返回失败
base = event_base_new();
if(!base)
{
cerr << "event base new failed." << endl;
return ERROR;
}
}
else
{
//确认特征那些生效
int f = event_base_get_features(base);
if(f&EV_FEATURE_ET)
{
cout << "EV_FEATURE_ET events are supported." << endl;
}
else
{
cout << "EV_FEATURE_ET events are not supports." << endl;
}
if(f&EV_FEATURE_O1)
{
cout << "EV_FEATURE_O1 events are supported." << endl;
}
else
{
cout << "EV_FEATURE_O1 events are not supports." << endl;
}
if(f&EV_FEATURE_FDS)
{
cout << "EV_FEATURE_FDS events are supported." << endl;
}
else
{
cout << "EV_FEATURE_FDS events are not supports." << endl;
}
if(f&EV_FEATURE_EARLY_CLOSE)
{
cout << "EV_FEATURE_EARLY_CLOSE events are supported." << endl;
}
else
{
cout << "EV_FEATURE_EARLY_CLOSE events are not supports." << endl;
}
cout << "event base new with config sucess" << endl;
event_base_free(base);
}
return 0;
}
```
### 创建`test_signal`
使用`libevent`处理信号,当信号来的时候使用`libevent`封装的函数调用回调函数,处理具体的信号事物。
```c
#include
#include
#include
#include "event_interface.h"
using namespace std;
//sock 文件描述符,which事件类型 arg 传递的参数
static void Ctrl_C(int sock, short which, void *arg)
{
cout << "Ctrl + C" << " 添加 " << endl;
}
// Kill函数
static void Kill(int sock, short which, void *arg)
{
cout << "Kill"<< endl;
struct event *ev = (struct event *)arg;
// 如果处于非待决状态
if(!evsignal_pending(ev, NULL))
{
event_del(ev);
event_add(ev, NULL);
}
}
int main(int argc, const char** argv) {
event_base *base = event_base_new();
//添加CTRL+c 信号事件 处于np pending
//隐藏的状态 EV_SIGNAL|EV_PERSIST
struct event *csig = evsignal_new(base, SIGINT, Ctrl_C, base);
if(!csig)
{
cerr << "SIGINT evsignal_new failed!" << endl;
return ERROR;
}
//添加事件到pending状态
if(event_add(csig, 0) != 0)
{
cerr << "SIGINT event_add failed!"<< endl;
return ERROR;
}
//添加Kill信号 SIGTERM
// 非持久只进入一次
// event_self_cbarg 传递当前的event
event *ksig = event_new(base, SIGTERM, EV_SIGNAL, Kill, event_self_cbarg());
if(!ksig)
{
cerr << "SIGTERM evsignal_new failed." << endl;
return ERROR;
}
// 添加事件到pending
if(event_add(ksig, NULL))
{
cerr << "SIGTERM event_add failed." << endl;
return ERROR;
}
//进入事件主循环
event_base_dispatch(base);
event_free(csig);
event_free(ksig);
event_base_free(base);
return 0;
}
```
### 创建`test_timer`
`libevent`支持定时触发事件,并且定时触发事件支持调用优化,
```c
#include
#include
#include
#include "event_interface.h"
#include
using namespace std;
// | s | us |
static timeval t1 = {5,0};
void timer1(int sock, short which, void *arg)
{
cout << "{timer1}" << endl;
event *ev = (event*)arg;
// no pending
if(!evtimer_pending(ev, &t1))
{
evtimer_del(ev);
evtimer_add(ev, &t1);
}
}
/* 调用的函数内部不能进行延时,需要加延时可以在外部进行添加 */
// 否则可能造成计时不准确
void timer2(int sock, short which, void *arg)
{
cout << "[timer2]"<