环境搭建

由于一开始在Macos上安装lib event遇到了一点小问题,后改用在ubuntu上安装并成功运行事例代码。之后又觉得不能放弃Mac上的环境搭建,于是开始折腾如何安装libevent。

安装C++通用包管理器

vcpkg是一个跨平台的C++包管理器,有了它可以很方便安装各种包

安装vckpg

首先编译安装vcpkg

vcpkg卡在下载Cmake…

使用clashX开启终端代理,成功安装vcpkg

之后

1
2
./vcpkg serach libevent
./vcpkg install libevent

libevent安装完成

初步使用libevent

封装event_base

libevent存在类似于libcurl中的curl这种全局资源,因此使用RAII对其进行初步封装,以便实现资源的自动管理。

设置evconnlistener

此函数用于设置感兴趣的事件,监听的端口已经base,回掉函数等参数。

回掉函数

由于libevent使用的是C语言,回掉函数的类型其实已经写死了,但是我们可以通过回掉函数设置的参数来传递我们自动的funtion和arg。以下是默认的回掉函数定义

1
void listen_callback(struct evconnlistener *e, evutil_socket_t s, struct sockaddr * addr, int socklen, void *arg)

事件分发

event_base_dispatch

暂时还没看懂这个函数的作用,但是函数参数为event_base*,初步猜测应该是通过event_base来确定分发事件的。

初探代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <csignal>
#include <event2/event.h>
#include <event2/listener.h>
#include <iostream>
#include <memory>
#include <functional>
#include <future>

#define VNAME(value) (#value)

using namespace std;

template<class T>
inline static void error_nullptr(const std::string& str, const T& instance)
{
if(instance == nullptr)
{
std::cout<<str<<"failed\n";
exit(0);
}
}

template<class F,class S>
inline static void free_source(F&& fn,S&& arg)
{
if(arg) fn(arg);
arg = nullptr;
}

template <class T = int>
class Callback
{
public:
template<class A,class ...args>
Callback(A&& fn,args&&... arg):f(std::bind(fn,arg...)){}
T instance()
{
return f();
}
std::function<T()> f;
};

void listen_callback(struct evconnlistener *e, evutil_socket_t s, struct sockaddr * addr, int socklen, void *arg)
{
std::cout<<reinterpret_cast<Callback<int>*>(arg)->instance()<<std::endl;
}

class Base
{
public:
Base(int port,evconnlistener_cb callback,Callback<int>& param): eb_instance(nullptr)
{
eb_instance = event_base_new();
error_nullptr(VNAME(eb_instance), eb_instance);
//sock,bind,listen,dispatch
sockaddr_in sock;
memset(&sock,0, sizeof(sock));
sock.sin_family = AF_INET;
sock.sin_port = htons(port);
//lib event的上下文
ec_listener = evconnlistener_new_bind(eb_instance,//event_base
callback,//回掉函数
(void*)&param,//callback的参数
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
128,//listen 中的backlog(全连接队列长度)
(sockaddr*)&sock, // 绑定端口号
sizeof(sock));

error_nullptr(VNAME(ec_listener), ec_listener);
event_base_dispatch(eb_instance);
}
~Base()
{
free_source(evconnlistener_free, ec_listener);
free_source(event_base_free, eb_instance);
}
event_base* get_instance()
{
return eb_instance;
}
private:
event_base* eb_instance;
evconnlistener* ec_listener;
};

int two_sum(int a,int b)
{
return a+b;
}

int main() {
Callback<int>two(two_sum,10,20);
std::shared_ptr<Base>bases = std::make_shared<Base>(9999,listen_callback, two);
return 0;
}