赞
踩
Libevent: 是开源社区的一款高性能的I/O框架库。 其学习和使用者众多,例如:高性能的分布式内存对象缓存软件memcached,Google浏览器Chromium的Linux版本。
Libevent使用特点:
1.跨平台支持: Libevent支持Linux,UINX和Windows。
2.统一事件源: Libevent对I/O事件、信号和定时事件提供统一的处理。
3.线程安全: Libevent使用Libevent_pthreads库来提供线程安全支持。
4.基于Reactor模式实现: 该模式主线程只负责监听文件描述符上是否有事件发生,有的话就立即将该事件通知工作线程,除此之外,主线程不做任何其他实质性工作。读写数据,接受新的连接,以及处理客户请求均在工作线程中完成。
使用模型:
大致使用流程:
1.应用程序进行event事件处理器的定义。
2.将event事件处理器注册到Libevent中。
3.Libevent进行循环监听事件,利用I/O复用方法检测就绪事件。
4.得到就绪事件,在就绪队列中由应用程序进程回调函数调用。
Libevent支持的事件类型:
下面我们利用定时事件与信号事件来看一看Libevent的简单实用(更多详情请参考:Linux高性能服务器编程)。
几个函数的作用:
1.event_init()函数用于创建event_base对象,一个event_base对象相当于一个Reactor实例。
2.evsignal_new()创建信号事件处理器,evtimer_new创建定时事件处理器。
3.event_add()函数将事件处理器添加到注册事件队列中,并将该事件处理器对应的事件添加到事件多路分发器中。
4.event_base_dispatch()函数执行事件循环。
5.事件循环结束后,event_free()释放系统资源。
#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("SIGINT was call\n"); } //定时事件 void time_cb(int fd, short event, void *arg) { printf("time out\n"); } int main() { struct event_base *base = event_init(); //base为Libevent的一个实例,对base进行初始化 //创建信号事件 struct event *signal_event = evsignal_new(base, SIGINT, signal_cb, NULL); event_add(signal_event, NULL); //将事件注册到Libevent中 //创建定时事件 struct timeval tm = {5, 0}; //定时时间 struct event *time_event = evtimer_new(base, time_cb, NULL); event_add(time_event, &tm); //将事件注册到Libevent中 //执行事件循环,检测就绪事件 event_base_dispatch(base); //事件循环结束,释放资源 event_free(signal_event); event_free(time_event); event_base_free(base); exit(0); }
测试结果(以下代码均为Linux下测试):使用Libevent时要链入libevent库:
1.定时事件被触发: 若5s内不做任何处理,定时事件便会被触发
2.信号事件被触发: 触发会输出SIGINT was call,SIGINT事件为程序终止(interrupt)信号, 在用户键入Ctrl+C时发出。
使用Libevent库实现TCP服务器时,将监听的socket与连接时的socket分别生成一个Libevent(指定其对应的回调函数),并将其添加到Libevent的另一个base中,执行事件循环检测其发生。
客户端代码:
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> #include <unistd.h> #include <event.h> #include <signal.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAX_CLIENT 100 //最多客户端 #define DATALENGTH 1024 //缓冲区大小 //定义一个全局事件处理器 struct event_base *base = NULL; typedef struct ClientData { int fd; struct event *listen_event; }ClientData; void InitClients(ClientData clients[]) { int i = 0; for (; i < MAX_CLIENT; ++i) { clients[i].fd = -1; clients[i].listen_event = NULL; } } void InsertToClients(ClientData clients[], int fd, struct event *listen_event) { int i = 0; for (; i < MAX_CLIENT; ++i) { if (clients[i].fd == -1) { clients[i].fd = fd; clients[i].listen_event = listen_event; 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].listen_event; } } return NULL; } //创建套接字 int CreateSocket() { int listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd == -1) { return -1; } struct sockaddr_in ser_addr; memset(&ser_addr, 0, sizeof(ser_addr)); ser_addr.sin_family = AF_INET; ser_addr.sin_port = htons(6000); ser_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); int res = bind(listenfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr)); if (res == -1) { return -1; } res = listen(listenfd, 5); if (res == -1) { return -1; } return listenfd; } //处理客户端数据 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 *listen_event = DeleteOfClients(clients, fd); event_free(listen_event); printf("one client unlink!\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 cli_addr; socklen_t len = sizeof(cli_addr); int c = accept(fd, (struct sockaddr*)&cli_addr, &len); if (c < 0) { return; } struct event *listen_event = event_new(base,c, EV_READ | EV_PERSIST, client_fun, arg); InsertToClients(clients, c, listen_event); event_add(listen_event, NULL); printf("one client link!\n"); } int main() { int sockfd = CreateSocket(); assert(sockfd != -1); ClientData clients[MAX_CLIENT]; InitClients(clients); base = event_init(); //针对与listenfd创建事件 struct event *listen_event = event_new(base, sockfd, EV_READ | EV_PERSIST, sockfd_fun, (void*)clients); event_add(listen_event, NULL); //执行事件循环,检测就绪事件 event_base_dispatch(base); //事件循环结束,释放资源 event_free(listen_event); event_base_free(base); exit(0); }
服务器代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <assert.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); assert(sockfd != -1); struct sockaddr_in ser_addr; memset(&ser_addr, 0, sizeof(ser_addr)); ser_addr.sin_family = AF_INET; ser_addr.sin_port = htons(6000); ser_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //connect完成与与服务器的连接,所以sockaddr应该给服务器的地址信息 int res = connect(sockfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr)); assert(res != -1); while (1) { char buff[128] = {0}; printf("input:"); fgets(buff, 127, stdin); if (strncmp(buff, "end", 3) == 0) { break; } int num = send(sockfd, buff, strlen(buff)-1, 0); assert(num != -1); if (num == 0) //未写入进去数据 { printf("the length send data is 0\n"); break; } char recvbuff[128] = {0}; int n = recv(sockfd, recvbuff, 127, 0); assert(n != -1); if (n == 0) { printf("recv data error\n"); break; } printf("recv data is : %s\n", recvbuff); } close(sockfd); exit(0); }
测试结果:
一个客户端:
多个客户端:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。