安装
下载
管网
找到合适的版本,并击下载,解压到合适的地方
tar -xzvf libevent-xxx.tar.gz
编译和安装
./configure
make
sudo make install
文档
官方给的文档,打不开,为此在github找到了文档的项目,clone并编译即可
git地址
https://gitee.com/cocosleep/libevent-book.git
编译
编译之前还需要安装 asciidoc
suod apt install asciidoc
make
编译之后生成很多html文件,把它们移动到一个指定的空文件
mv *.html html/
TOC.html就是整个文档的索引。
基于 event_base
的 tcp 服务器框架
创建销毁 event_base
struct event_base* event_base_new(void);
void event_base_free(struct event_base* event);
添加监听节点
#define EV_TIMEOUT 0x01
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10
#define EV_ET 0x20
typedef void(*event_callback_fn)(int fd, short event, void* arg);
struct event* event_new(struct event_base* base, int fd, short event, env_callback_fn cb, void* arg);
void *event_self_cbarg();
// 用法
// event_new(base, 0, EV_READ|EV_PERSIST, cb, event_self_cbarg());
int event_add(struct event* ev, const struct timeval* tv);
int event_del(struct event* ev);
/*
* 先调用 event_del 然后再free
*/
void event_free(struct event* event);
事始事件循环
int event_base_despatch(struct event_base* event);
例子
#include <stdio.h>
#include <event.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int ipv4bind(short port, const char* ip)
{
struct sockaddr_in sin;
sin.sin_addr.s_addr = 0;
if(ip != NULL)
{
inet_aton(ip, &sin.sin_addr);
}
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
return -1;
}
int val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
{
close(fd);
fprintf(stderr, "bind error\n");
return -1;
}
return fd;
}
void read_cb(int fd, short event, void* arg)
{
struct event* ev = (struct event*) arg;
char buf[1500];
int nRead = read(fd, buf, 1500);
if(nRead <= 0)
{
event_free(ev);
return;
}
write(fd, buf, nRead);
}
void accept_cb(int fd, short event, void* arg)
{
printf("accept \n");
struct event_base* base = (struct event_base* ) arg;
struct sockaddr_in sin;
sin.sin_family = AF_INET;
socklen_t len = sizeof(sin);
int cfd = accept(fd,(struct sockaddr*)&sin, &len);
if(cfd == -1)
{
fprintf(stderr, "accept error \n");
return;
}
struct event* ev = event_new(base, cfd, EV_READ|EV_PERSIST, read_cb, event_self_cbarg());
event_add(ev, NULL);
const char* msg = "Hello client\n";
write(cfd, msg, strlen(msg));
}
int main()
{
struct event_base* base = event_base_new();
if(base == NULL)
{
fprintf(stderr, "event_base_new error\n");
return 1;
}
int fd = ipv4bind(8888, NULL);
if(fd == -1)
{
fprintf(stderr, "error ivp4bind\n");
return 1;
}
if(listen(fd, 128)==1)
{
fprintf(stderr, "listen error\n");
return 1;
}
struct event* ev = event_new(base,fd, EV_READ|EV_PERSIST,accept_cb, base);
event_add(ev, NULL);
event_base_dispatch(base);
event_free(ev);
event_base_free(base);
return 0;
}
bufferevent
事件标志
BEV_EVENT_READING
BEV_EVENT_WRITING
BEV_EVENT_ERROR -- EVUTIL_SOCKET_ERROR() 获取错信息
BEV_EVENT_TIMEOUT
BEV_EVENT_EOF
BEV_EVENT_CONNECTED
bufferevents标志选项
BEV_OPT_CLOSE_ON_FREE
BEV_OPT_THREADSAFE
BEV_OPT_DEFER_CALLBACKS
BEV_OPT_UNLOCK_CALLBACKS
truct bufferevent *bufferevent_socket_new(
struct event_base *base,
evutil_socket_t fd,
enum bufferevent_options options);
可以给fd指定-1,之后通过 bufferevent_setfd
设置
创建bufferevent之后可以给它指定一些回调函数
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
typedef void (*bufferevent_event_cb)(struct bufferevent *bev,
short events, void *ctx);
void bufferevent_setcb(struct bufferevent *bufev,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg);
事件的使能配置
void bufferevent_enable(struct bufferevent *bufev, short events);
void bufferevent_disable(struct bufferevent *bufev, short events);
short bufferevent_get_enabled(struct bufferevent *bufev);
events 选项
EV_READ
EV_WRITE
释放 bufferevent
void bufferevent_free(struct bufferevent *bev);
如果在创建时指定了BEV_OPT_CLOSE_ON_FREE
,释放时会关闭对应的fd
例子
#include <stdio.h>
#include <event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int ipv4bind(short port, const char* ip)
{
struct sockaddr_in sin;
sin.sin_addr.s_addr = 0;
if(ip != NULL)
{
inet_aton(ip, &sin.sin_addr);
}
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
return -1;
}
int val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
{
close(fd);
fprintf(stderr, "bind error\n");
return -1;
}
return fd;
}
void readcb(struct bufferevent* bev, void* arg)
{
// 还有更多的 bufferevent_函数
char buf[1500];
int nRead = bufferevent_read(bev, buf, 1500);
bufferevent_write(bev, buf, nRead);
}
void eventcb(struct bufferevent* bev, short event, void* arg)
{
if(event & BEV_EVENT_EOF)
{
printf("close \n");
bufferevent_free(bev);
}
if(event & BEV_EVENT_CONNECTED)
{
printf("connected \n");
}
}
void acceptcb(int fd, short event, void* ctx)
{
struct event_base* base = (struct event_base*)ctx;
struct sockaddr_in sin;
sin.sin_family = AF_INET;
socklen_t len = sizeof(sin);
int cfd = accept(fd, (struct sockaddr*)&sin, &len);
if(cfd != -1)
{
// bufferevent 提供内置缓冲区,要吧更方便的进行数据读写
struct bufferevent* cbev = bufferevent_socket_new(base, cfd, BEV_OPT_CLOSE_ON_FREE);
if(cbev == NULL)
{
printf("error \n");
}
bufferevent_setcb(cbev, readcb, NULL, eventcb, NULL);
bufferevent_enable(cbev, EV_READ);
}
}
int main()
{
struct event_base* base = event_base_new();
if(base == NULL)
{
return 1;
}
int fd = ipv4bind(8888, NULL);
listen(fd, 128);
// 这个没有读写操作,使用bufferevent没有意义
struct event* ev = event_new(base, fd, EV_READ|EV_PERSIST, acceptcb, base);
event_add(ev, NULL);
event_base_dispatch(base);
event_base_free(base);
}
TCP连接侦听器
struct evconnlistener *evconnlistener_new(struct event_base *base,
evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
evutil_socket_t fd);
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
const struct sockaddr *sa, int socklen);
void evconnlistener_free(struct evconnlistener *lev);
flags可以取以下值
LEV_OPT_LEAVE_SOCKETS_BLOCKING
默认创建的socket是非阻塞的
LEV_OPT_CLOSE_ON_FREE
释放时关闭
LEV_OPT_CLOSE_ON_EXEC
执行exec函数时关闭
LEV_OPT_REUSEABLE
复用?
LEV_OPT_THREADSAFE
线程完全
LEV_OPT_DISABLED
创建时使用其无效, 可以用 evconnlistener_enable() 为其使用能
监听器的回调函数
typedef void (*evconnlistener_cb)(struct evconnlistener *listener,
evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr);
设置监听回调函数
int evconnlistener_disable(struct evconnlistener *lev);
int evconnlistener_enable(struct evconnlistener *lev);
错误回调
typedef void (*evconnlistener_errorcb)(struct evconnlistener *lis, void *ptr);
void evconnlistener_set_error_cb(struct evconnlistener *lev,
evconnlistener_errorcb errorcb);
使用能函数
int evconnlistener_disable(struct evconnlistener *lev);
int evconnlistener_enable(struct evconnlistener *lev);
获取数据
evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);
struct event_base *evconnlistener_get_base(struct evconnlistener *lev);
使用TCP侦听连接器
#include <stdio.h>
#include <event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
void readcb(struct bufferevent* bev, void* arg)
{
printf("read \n");
char buf[1500];
int nRead = bufferevent_read(bev, buf, 1500);
bufferevent_write(bev, buf, nRead);
}
void eventcb(struct bufferevent* bev, short event, void* arg)
{
if(event & BEV_EVENT_EOF)
{
printf("close \n");
bufferevent_free(bev);
}
if(event & BEV_EVENT_CONNECTED)
{
printf("connected \n");
}
}
void listen_cb(struct evconnlistener* listen, int fd, struct sockaddr* addr, int len, void* ctx)
{
struct event_base* base = evconnlistener_get_base(listen);
struct sockaddr_in sin;
struct bufferevent* cbev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if(cbev == NULL)
{
printf("error \n");
}
bufferevent_setcb(cbev, readcb, NULL, eventcb, NULL);
bufferevent_enable(cbev, EV_READ);
}
int main()
{
struct event_base* base = event_base_new();
if(base == NULL)
{
return 1;
}
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(8888);
sa.sin_addr.s_addr = 0;
struct evconnlistener* listener = evconnlistener_new_bind(
base, listen_cb, NULL,
LEV_OPT_CLOSE_ON_FREE,
-1, (struct sockaddr*)&sa, sizeof(sa)
);
event_base_dispatch(base);
event_base_free(base);
}
tcp客户端
int bufferevent_socket_connect(struct bufferevent* bev, struct socketaddr* addr, int addrlen);
#include <stdio.h>
#include <event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
void readcb(struct bufferevent* bev, void* ctx)
{
char buf[1500];
int nRead = bufferevent_read(bev, buf, 1500);
write(STDOUT_FILENO, buf, nRead);
}
void eventcb(struct bufferevent* bev, short events, void* ctx)
{
if(events & BEV_EVENT_EOF)
{
printf("closed \n");
bufferevent_free(bev);
}
if(events & BEV_EVENT_CONNECTED)
{
printf("connected\n");
}
}
void in_eventcb(int fd, short events, void* ctx)
{
struct bufferevent* bev = (struct bufferevent*)ctx;
char buf[1500];
int nRead = read(fd, buf, 1500);
bufferevent_write(bev, buf, nRead);
}
int main()
{
struct event_base* base = event_base_new();
if(base == NULL)
{
return 1;
}
struct bufferevent* bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, readcb, NULL, eventcb, NULL);
bufferevent_enable(bev, EV_READ);
struct sockaddr_in sa;
sa.sin_port = htons(8888);
sa.sin_family = AF_INET;
inet_aton("127.0.0.1", &sa.sin_addr);
bufferevent_socket_connect(bev, (struct sockaddr*)&sa, sizeof(sa));
struct event* ev = event_new(base, STDIN_FILENO, EV_READ|EV_PERSIST, in_eventcb, bev);
event_add(ev, NULL);
event_base_dispatch(base);
event_base_free(base);
return 0;
}