文章目录
- 一、Libevent概述
- [二、libevent IO事件](#二、libevent IO事件)
- 三、libevent信号事件
- 四、libevent高并发服务器
- 参考
一、Libevent概述
Libevent 是一个用C语言编写的、轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。
Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、 Vomit、 Nylon、 Netchat等等。Libevent之于C语言网络编程,类似于Nettty之于Java Web编程。学习Netty的小伙伴,不防看下Libevent的实现,会加深对Netty框架的理解
安装方式(1):
bash
$ apt-get download libevent-dev
$ dpkg -x libevent-dev_2.1.12-stable-1build3_amd64.deb libevent
安装方式():
- libevent的download urls
- github assert
1.两个重要的结构体
struct event-base
- 事件集合
- struct event_base用于创建和管理事件循环,而struct event用于表示具体的事件,并与事件循环相关联。
- struct event_base 代表一个事件处理的基础框架,它负责管理事件循环(event loop),接收事件并将它们分派给相应的事件处理器。
- struct event_base 实例典型地代表了一个事件驱动程序的运行环境,它可以被视为事件循环的主体。
- struct event_base 可以支持多种事件驱动的后端(如select、poll、epoll等),因此在创建 struct event_base 实例时,可以指定使用的后端。
struct event
- 一个事件(可以是一个fd,也可以是一个signal,也可以是一个定时器事件)
- struct event 包含了事件的相关信息,比如事件类型(读、写、定时器等)、事件触发时需要执行的回调函数等。
- 当文件描述符上发生关注的事件时,struct event 将通知 struct event_base,然后 struct event_base 将事件分派给相应的事件处理器执行。
两者关系:
- struct event结构体中有一个指向struct event_base的指针,用于指示该事件所属的事件循环。这样,当事件发生时,事件循环可以根据事件的描述找到相应的回调函数并执行。
2.libevent常用接口
event_init
- 用于初始化 libevent 的全局状态。在使用 libevent 前调用此函数是必要的步骤,它会进行一些全局状态的初始化工作。
event_base new
- event_base_new 用于创建一个新的事件基础框架(struct event_base 实例)。
- 返回的 event_base 实例将用于管理事件循环和事件处理。
event_set
- event_set 用于设置事件的相关属性,比如事件关联的文件描述符、事件类型、以及事件触发时执行的回调函数。
这个函数被废弃了,不建议使用,建议使用 event_assign 替代。
event_assign
- event_assign 用于将事件与指定的 event_base 关联起来,并设置事件的属性。
- 这个函数类似于 event_set,但是更加灵活,可以避免一些使用上的混淆。
event_add
- event_add 用于向事件循环中添加一个事件,让它开始监视文件描述符上的事件。
- 添加事件后,事件循环将开始监视文件描述符,当有事件发生时,会触发事件的回调函数。
evconnlistener_new_bing
- evconnlistener_new_bind 是用于创建一个监听器(listener)的函数,用于监听指定地址和端口上的连接请求。
- 当有连接请求到达时,监听器将接受连接并创建一个新的套接字来处理该连接。
二、libevent IO事件
fifo-read.c
c
#include <event.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
void fifo_read(evutil_socket_t fd, short events, void *arg) {
char buf[32] = {0};
int rt = read(fd, buf, sizeof(buf));
if (-1 == rt) {
perror("read");
exit(-1);
}
printf("read <%s>\n", buf);
return;
}
int main() {
int ret = mkfifo("fifo.tmp", 0700);
if (-1 == ret) {
perror("mkfifo");
exit(-1);
}
int fd = open("fifo", O_RDONLY);
if (-1 == fd) {
perror("open");
exit(-1);
}
struct event ev;
event_init();
event_set(&ev, fd, EV_READ, fifo_read, NULL);
event_add(&ev, NULL);
event_dispatch();
return 0;
}
fifo-write.c
c
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main() {
int fd = open("fifo.tmp", O_WRONLY);
if (-1 == fd) {
perror("open");
exit(-1);
}
char buf[32] = {0};
while (1) {
scanf("%s", buf);
int ret = write(fd, buf, sizeof(buf));
if (-1 == ret) {
perror("write");
exit(-1);
}
if (!strcmp(buf, "bye")) {
break;
}
memset(buf, 0, sizeof(buf));
}
return 0;
}
三、libevent信号事件
signal.c
c
#include <event2/event_compat.h>
#include <event2/event_struct.h>
#include <signal.h>
static int signal_count = 0;
void signal_handler(evutil_socket_t fd, short events, void *args) {
printf("<sig: %d>\n", fd);
++signal_count;
if (signal_count >= 2) {
event_del((struct event *)args);
}
}
int main() {
struct event_base *base = event_base_new();
struct event ev;
event_assign(&ev, base, SIGINT, EV_SIGNAL | EV_PERSIST, signal_handler, &ev);
event_add(ev, NULL);
event_base_dispatch();
event_base_free(base);
return 0;
}
四、libevent高并发服务器
c
#include <arpa/inet.h>
#include <cstddef>
#include <event2/bufferevent.h>
#include <event2/bufferevent_struct.h>
#include <event2/event_compat.h>
#include <event2/listener.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void read_cb(struct bufferevent *bev, void *ctx) {
char buf[128] = {0};
size_t ret = bufferevent_read(bev, buf, sizeof(buf));
if (ret < 0) {
exit(-1);
}
printf("read from: <%d>\n", *(int *)ctx);
}
void event_cb(struct bufferevent *bev, short what, void *ctx) {
if (what & BEV_EVENT_EOF)
printf("Client: <d> down", *(int *)ctx);
bufferevent_free(bev);
}
void listen_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *addr, int socklen, void *arg)
{
static int gFd = -1;
printf("Accept: <%d>\n", fd);
gFd = fd;
struct event_base *base = arg;
struct bufferevent *bev =
bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if (NULL == bev) {
exit(-1);
}
bufferevent_setcb(bev, read_cb, NULL, event_cb, &gFd);
bufferevent_enable(bev, EV_READ);
}
int main() {
struct event_base *base = event_base_new();
if (NULL == base) {
printf("event_base \n");
exit(-1);
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = 8000;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
struct evconnlistener *listen = evconnlistener_new_bind(
base, listen_cb, NULL, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 10,
(const struct sockaddr *)&server_addr, sizeof(server_addr));
event_base_dispatch(base);
evconnlistener_free(listen);
event_base_free(base);
return 0;
}