libevent概述
Libevent 是开源社区的一款高性能的 I/O 框架库,使用 Libevent 的著名案例有:高性能的分布式内存对象缓存软件 memcached,Google 浏览器 Chromium 的 Linux 版本。作为一个 I/O 框架库,Libevent 具有如下特点:
◼ 跨平台支持。 Libevent 支持 Linux、Unix 和 Windows。
◼ 统一事件源。Libevent 对 I/O 事件、信号和定时事件提供统一的处理。
◼ 线程安全。Libevent 使用 libevent_pthreads 库来提供线程安全支持。
◼ 基于 Reactor 模式的实现。
使用示例
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <event.h>
#include <signal.h>
void signal_cb(int fd, short event, void *arg)
{
printf("%d Signal triggered\n");
}
void timeout_cb(int fd, short event, void *arg)
{
printf("timeout\n");
}
int main()
{
struct event_base *base = event_init();
struct event *signal_event = evsignal_new(base, SIGINT, signal_cb,NULL);
event_add(signal_event, NULL);
struct timeval tv = { 2, 0 };
struct event *timeout_event = evtimer_new(base, timeout_cb, NULL);
event_add(timeout_event, &tv);
event_base_dispatch(base);
event_free(signal_event);
event_free(timeout_event);
event_base_free(base);
exit(0);
}
/*
define evsignal_new(b, x, cb, arg) \
event_new((b), (x), EV_SIGNAL | EV_PERSIST, (cb), (arg))
#define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg))
struct event *event_new(struct event_base *base, evutil_socket_t fd,
short events, void (*cb)(evutil_socket_t, short, void*), void *arg);
*/
libevent支持事件类型
#define EV_TIMEOUT | 0x01 | /* 定时事件 */ |
---|---|---|
#define EV_READ | 0x02 | /* 可读事件 */ |
#define EV_WRITE | 0x04 | /* 可写事件 */ |
#define EV_SIGNAL | 0x08 | /* 信号事件 */ |
#define EV_PERSIST | 0x10 | /* 永久事件 */ |
/* 边沿触发事件,需要 I/O 复用系统调用支持,比如 epoll */ #define EV_ET 0x20
服务器端:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <event.h>
#define MAX_CLIENT 100
#define DATALENGTH 1024
struct event_base *base = NULL;
typedef struct ClientData
{
int fd;
struct event *ev;
}ClientData;
void InitClients(ClientData clients[])
{
int i = 0;
for (; i < MAX_CLIENT; ++i)
{
clients[i].fd = -1;
clients[i].ev = NULL;
}
}
void InsertToClients(ClientData clients[], int fd, struct event *ev)
{
int i = 0;
for (; i < MAX_CLIENT; ++i)
{
if (clients[i].fd == -1)
{
clients[i].fd = fd;
clients[i].ev = ev;
break;
}
}
}
struct event * DeleteOfClients(ClientData clients[], int fd)
{
int i = 0;
for (; i < MAX_CLIENT; ++i)
{
if (clients[i].fd == fd)
{
clients[i].fd = -1;
return clients[i].ev;
}
}
return NULL;
}
//初始化 socket
int InitSocket()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) return -1;
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
if (res == -1) return -1;
res = listen(sockfd, 5);
if (res == -1) return -1;
return sockfd;
}
void client_fun(int fd, short event, void *arg)
{
ClientData *clients = (ClientData*)arg;
char buff[DATALENGTH] = { 0 };
int n = recv(fd, buff, DATALENGTH - 1, 0);
if (n <= 0)
{
struct event *ev = DeleteOfClients(clients, fd);
event_free(ev);
printf("A Client Disconnect\n");
return;
}
printf("%d:%s\n", fd, buff);
send(fd, "OK", 2, 0);
}
void sockfd_fun(int fd, short event, void *arg)
{
ClientData *clients = (ClientData*)arg;
struct sockaddr_in caddr;
socklen_t len = sizeof(caddr);
int c = accept(fd, (struct sockaddr*)&caddr, &len);
if (c < 0)
{
return;
}
struct event *ev = event_new(base, c, EV_READ | EV_PERSIST, client_fu n, arg);
InsertToClients(clients, c, ev);
event_add(ev, NULL);
printf("A client Link\n");
}
int main()
{
int sockfd = InitSocket();
assert(sockfd != -1);
ClientData clients[MAX_CLIENT];
InitClients(clients);
base = event_init();
struct event *ev = event_new(base, sockfd, EV_READ | EV_PERSIST, soc kfd_fun, (void*)clients);
event_add(ev, NULL);
event_base_dispatch(base);
event_free(ev);
event_base_free(base);
exit(0);
}