一个类似 libevent , libev 的事件驱动库,当然目前的功能还非常简单,不过基本框架已建立,功能会慢慢加上。
目前支持 freeBSD 和 linux 。在 freeBSD 上使用kqueue
,在 linux 上使用epoll
。
https://github.com/luohaha/libel
el_loop *el_loop_new()
创建新的 event loop
event *el_event_new(int fd, int flags, void (*cb) (int fd, int size, void *arg), void arg)
创建新的事件.
fd : the file descriptor that you want to listen.
flags :READ_EVENT
orWRITE_EVENT
or both
cb : callback function that will be called by libel
arg : it will be pass to callback function
void el_event_add(el_loop *loop, event *e)
将事件注册到 event loop 上
int el_loop_run(el_loop *loop)
启动 loop
void el_loop_free(el_loop *loop)
回收 loop
void error(const char *msg)
错误处理
一个服务器端接收多个客户端请求的例子。
server
#include<libel/el.h>
/**
create a listener
**/
int create_listener() {
int listenfd;
struct sockaddr_in *servaddr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
error("socket error!");
servaddr->sin_family = AF_INET;
servaddr->sin_port = htons(3333);
if (inet_pton(AF_INET, "0.0.0.0", &servaddr->sin_addr) < 0)
error("inet_pton error!");
if (bind(listenfd, (struct sockaddr *)servaddr, sizeof(struct sockaddr_in)) < 0)
error("bind error!");
if (listen(listenfd, LISTENQ) < 0)
error("listen error!");
return listenfd;
}
/**
处理客户端发送过来的数据,打印数据。
*/
void onread(int fd, int size, void *arg) {
el_loop *loop = (el_loop*)arg;
char buf[MAXLINE];
int n;
while ((n = read(fd, buf, MAXLINE)) > 0) {
buf[n] = '\0';
printf("%s", buf);
}
if (n == 0) {
//客户端已经完成数据的发送。关闭连接。
close(fd);
} else if (n < 0) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
//如果客户端未发送数据完成,需要继续监听
event *e = el_event_new(fd, READ_EVENT, onread, loop);
el_event_add(loop, e);
return;
} else
error("read from connected socket error!");
}
}
/*
处理客户端发起连接的回调函数
*/
void onaccept(int fd, int size, void *arg) {
el_loop *loop = (el_loop*)arg;
int i;
//size 为缓冲区中的字节数
for (i = 0; i < size; i++) {
int connfd;
if (( connfd = accept(fd, NULL, NULL)) < 0) {
if (errno == EWOULDBLOCK || errno == ECONNABORTED
|| errno == EINTR || errno == EPROTO) {
continue;
} else
error("accept error!");
}
/**
将新建立的连接新建为事件,并加入 loop 。回调函数为 onread 。
*/
event *e = el_event_new(connfd, READ_EVENT, onread, loop);
el_event_add(loop, e);
/**
在 libel 的处理机制中,每次事件触发并处理完成后,都会从 loop 中删除,
所以需要重新创建,并加入 loop
*/
event *old = el_event_new(fd, READ_EVENT, onaccept, loop);
el_event_add(loop, old);
}
}
int main() {
//创建监听
int listenfd = create_listener();
//新建 loop
el_loop *loop = el_loop_new();
//新建要监听的事件,回调函数为 onaccept
event *e = el_event_new(listenfd, READ_EVENT, onaccept, loop);
//将要监听的事件注册到 loop 上
el_event_add(loop, e);
//启动 loop
return el_loop_run(loop);
}
client
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/time.h>
#include<arpa/inet.h>
#include<errno.h>
#include<string.h>
#define MAX 1024
int main() {
int sockfd;
struct sockaddr_in servaddr;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "socket error!\n");
exit(-1);
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(3333);
if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) < 0) {
fprintf(stderr, "inet_pton error!\n");
exit(-1);
}
if (connect(sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0) {
fprintf(stderr, "connect error!\n");
exit(-1);
}
char buf[MAX];
/**
客户端从终端接收数据,并向服务器端发送。
*/
while (fgets(buf, MAX, stdin) != NULL) {
if (write(sockfd, buf, strlen(buf)) < 0) {
fprintf(stderr, "write error!\n");
exit(-1);
}
}
close(sockfd);
return 0;
}
1
Balthild 2016-06-12 10:33:35 +08:00 via Android
nice
|
2
wadahana 2016-06-12 11:34:39 +08:00
对比 libev libevent libuv 有神马优势?
|