c 写的一个简单的事件驱动库 libel

2016-06-11 22:41:31 +08:00
 luohaha

libel 是什么

一个类似 libevent , libev 的事件驱动库,当然目前的功能还非常简单,不过基本框架已建立,功能会慢慢加上。
目前支持 freeBSD 和 linux 。在 freeBSD 上使用kqueue,在 linux 上使用epoll

项目地址

https://github.com/luohaha/libel

api

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 or WRITE_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;
}

2618 次点击
所在节点    分享创造
3 条回复
Balthild
2016-06-12 10:33:35 +08:00
nice
wadahana
2016-06-12 11:34:39 +08:00
对比 libev libevent libuv 有神马优势?
luohaha
2016-06-12 12:27:57 +08:00
@wadahana 其实底层的性能差不多,用的都是 epoll , kqueue 等。但是功能还没有它们那些多。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/284982

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX