赞
踩
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-2.1.11-stable.tar.gz
Ubuntu安装:apt-get install libevent-dev
原型:struct event_base *event_init(void)
struct event_base *event_init(void)
{
struct event_base *base = event_base_new_with_config(NULL);
if (base == NULL) {
event_errx(1, "%s: Unable to construct event_base", __func__);
return NULL;
}
current_base = base;
return (base);
}
初始化事件集合,其实就是调用了event_base_new_with_config( )
函数,创建event_base
对象,并且赋值给了全局变量struct evdns_base *current_base
。
原型:void event_set(struct event *ev, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg);
参数:
1)事件
2)关联的文件描述符
3)事件类型
4)回调函数
5)回调函数的参数
void event_set(struct event *ev, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
{
int r;
r = event_assign(ev, current_base, fd, events, callback, arg);
EVUTIL_ASSERT(r == 0);
}
初始化event事件(其实就是给结构体ev的成员赋值)
fd
表示事件对应的文件描述符,events
表示事件的类型,callback
是回调函数(即当fd满足条件时调用该函数),arg
表示给回调函数传递的参数。原型:int event_add(struct event *ev, const struct timeval *tv);
int event_add(struct event *ev, const struct timeval *tv)
{
int res;
if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
event_warnx("%s: event has no event_base set.", __func__);
return -1;
}
EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
res = event_add_nolock_(ev, tv, 0);
EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
return (res);
}
这个函数会让程序陷入死循环, 如果集合中没有事件可以监听,则返回
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <event.h> #include <fcntl.h> /* 当监听的事件满足条件的时候,会触发回调函数,通过回调函数读取数据 */ void fifo_read(evutil_socket_t fd, short events, void *arg) { char buf[32] = {0}; int ret = read(fd, buf, sizeof(buf)); if (-1 == ret) { perror("read"); exit(1); } printf("从管道读取: %s\n", buf); } int main() { int ret = mkfifo("fifo.tmp", 00700); if (-1 == ret) { perror("mkfifo"); exit(1); } int fd = open("fifo.tmp", O_RDONLY); if (-1 == fd) { perror("open"); exit(1); } // 创建事件 struct event ev; // 初始化事件集合 event_init(); // 初始化事件(把fd和事件ev绑定) // 参数:事件、关联的文件描述符、事件类型、回调函数、回调函数参数 event_set(&ev, fd, EV_READ | EV_PERSIST, fifo_read, NULL); //把事件添加到集合 event_add(&ev, NULL); //开始监吿 event_dispatch(); //死循玿 如果集合中没有事件可以监听,则返囿 exit(0); }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main() { int fd = open("fifo.tmp", O_WRONLY); if (-1 == fd) { perror("open"); exit(2); } char buf[128] = {0}; while (1) { scanf("%s", buf); if (write(fd, buf, strlen(buf)) == -1) { perror("write"); break; } if (!strcmp(buf, "bye")) break; memset(buf, 0, 128); } close(fd); return 0; }
原型:struct event_base *event_base_new(void);
struct event_base *event_base_new(void)
{
struct event_base *base = NULL;
struct event_config *cfg = event_config_new();
if (cfg) {
base = event_base_new_with_config(cfg);
event_config_free(cfg);
}
return base;
}
创建event_base对象
注意:采用event_base_new( )创建出来的事件集合,最后要用 event_base_free(base)
释放掉,因为event_base_new( )是在堆空间上进行创建的。
用于释放event_base_new( )
函数创建的集合
原型:int event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
1)事件
2)事件集合
3)关联的文件描述符
4)事件类型
5)回调函数
6)回调函数的参数
将指定事件集合中的事件与某一文件描述符进行关联
可监听事件集合当中的事件,和event_dispatch( )的作用相同
原型:event_del(struct event *ev);
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <event.h> int signal_count = 0; void signal_handler(evutil_socket_t fd, short events, void *arg) { struct event *ev = (struct event *)arg; printf("收到信号 %d\n", fd); signal_count++; if (signal_count >= 5) { // 把事件从集合中删除 event_del(ev); } } 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(base); // 释放集合 event_base_free(base); exit(0); }
运行结果(收到一次Ctrl+C就打印信息,收到五次之后退出):
常见步骤:
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 *listener);
参数 listener 是指向要释放的 TCP 监听器的指针
使用 evconnlistener_free() 函数释放监听器时,libevent 库将自动关闭监听器的文件描述符,并释放监听器所占用的内存。在释放监听器之后,应该将指向监听器的指针设置为 NULL,以避免出现悬空指针的问题。
需要注意的是,如果在释放监听器之前仍然有活动的连接,则这些连接将被关闭,并且可能会因为连接未正常关闭而导致数据丢失。因此,在释放监听器之前,应该确保已经停止了所有连接的事件循环,并且数据已经被正确地处理和发送。
struct bufferevent *bufferevent_socket_new(
struct event_base *base,
evutil_socket_t fd,
enum bufferevent_options options
);
bufferevent_setcb() 函数是 libevent 库中用于设置套接字缓冲区事件处理器回调函数的函数。
void bufferevent_setcb(
struct bufferevent *bev,
bufferevent_data_cb readcb,
bufferevent_data_cb writecb,
bufferevent_event_cb eventcb,
void *cbarg
);
int bufferevent_read(struct bufferevent *bev, void *data, size_t size);
void bufferevent_free(struct bufferevent *bev);
服务端
#include <stdio.h> #include <stdlib.h> #include <event.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <event2/listener.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) { printf("bufferevent_read error!\n"); } else { printf("read %s\n", buf); } } void event_cb(struct bufferevent *bev, short what, void *ctx) { if (what & BEV_EVENT_EOF) { printf("客户端下线\n"); bufferevent_free(bev); //释放bufferevent对象 } else { printf("未知错误\n"); } } void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg) { printf("接受%d的连接\n", fd); struct event_base *base = arg; //针对已经存在的socket创建bufferevent对象 //事件集合(从主函数传递来)、fd(代表TCP连接)、BEV_OPT_CLOSE_ON_FREE(如果释放bufferevent对象则关闭连接) struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); if (NULL == bev) { printf("bufferevent_socket_new error!\n"); exit(1); } //给bufferevent设置回调函数 //bufferevent对象、读事件回调函数、写事件回调函数、其他事件回调函数、参数 bufferevent_setcb(bev, read_cb, NULL, event_cb, NULL); //使能bufferevent对象 bufferevent_enable(bev, EV_READ); } // 常见步骤: /* socket bind listen accept */ int main() { //创建一个事件集合 struct event_base *base = event_base_new(); if (NULL == base) { printf("event_base_new error\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 = htons(8000); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //创建socket、绑定、监听、接受连接 //创建监听对象,在指定的地址上监听接下来的TCP连接 //事件集合、当有连接时调用的函数、回调函数参数、释放监听对象关闭socket|端口重复使用、监听队列长度、绑定信息 //返回值:监听对象 struct evconnlistener *listener = evconnlistener_new_bind(base, listener_cb, base, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 10, (struct sockaddr *)&server_addr,sizeof(server_addr)); if (NULL == listener) { printf("evconnlistener_new_bind error\n"); exit(1); } //监听集合中的事件 event_base_dispatch(base); //释放两个对象 evconnlistener_free(listener); event_base_free(base); exit(0); }
客户端:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> int main() { //创建socket int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == sockfd) { perror("socket"); exit(1); } //发起连接请求 struct sockaddr_in server_info; //保存服务器的信息 bzero(&server_info, sizeof(server_info)); server_info.sin_family = AF_INET; server_info.sin_port = htons(8000); server_info.sin_addr.s_addr = inet_addr("127.0.0.1"); if (connect(sockfd, (struct sockaddr *)&server_info, sizeof(server_info)) == -1) { perror("connect"); exit(2); } char buf[1024] = {0}; while (1) { scanf("%s", buf); if (send(sockfd, buf, strlen(buf), 0) == -1) { perror("send"); break; } if (!strcmp(buf, "bye")) break; bzero(buf, 1024); } close(sockfd); return 0; }
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。