{"id":20904531,"url":"https://github.com/luohaha/libel","last_synced_at":"2025-05-13T05:30:38.348Z","repository":{"id":37579837,"uuid":"60526268","full_name":"luohaha/libel","owner":"luohaha","description":"An event-driven library.","archived":false,"fork":false,"pushed_at":"2022-05-31T13:50:06.000Z","size":31,"stargazers_count":71,"open_issues_count":0,"forks_count":20,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-04-01T18:14:38.462Z","etag":null,"topics":["c","event-driven","libel","signal-handler","timer"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/luohaha.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-06-06T12:31:34.000Z","updated_at":"2024-04-25T01:54:56.000Z","dependencies_parsed_at":"2022-08-29T09:41:57.606Z","dependency_job_id":null,"html_url":"https://github.com/luohaha/libel","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luohaha%2Flibel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luohaha%2Flibel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luohaha%2Flibel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luohaha%2Flibel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/luohaha","download_url":"https://codeload.github.com/luohaha/libel/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253882652,"owners_count":21978526,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","event-driven","libel","signal-handler","timer"],"created_at":"2024-11-18T13:17:38.327Z","updated_at":"2025-05-13T05:30:38.001Z","avatar_url":"https://github.com/luohaha.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# libel\nAn event-driven library.  \nLibel execute a callback function when a specific event happen on a file descriptor, or a sepcific signal happen. And also after a timeout has been reached.\n\n### install\n\n```\nmake config\nmake\nmake install\n```\n\n### use to use\n\nAfter install libel, you need to add header: \n\n```\n#include\u003clibel/el.h\u003e\n```\n\nYou can compile your code using `-lel` like this:  \n\n```\ngcc -o test test.c -lel\n```\n\n\n### support\n\nLibel is a multi-platform support library, and now support freeBSD, OS X and linux.  \nNow libel use `kqueue` on freebsd(also OS X), and `epoll` on linux.\n\n### struct\n\n`el_loop`\n\u003eAn event loop.\n\n`event`\n\u003e An event.\n\n### api\n\n```c\nel_loop *el_loop_new()\n```\n\u003ecreate a new event loop.\n\n```c\nevent *el_event_new(int fd, int flags, void (*cb) (int fd, int size, void *arg), void *arg)\n```\n\u003ecreate a new event.  \n\u003efd : the file descriptor that you want to listen.  \n\u003eflags : `READ_EVENT` or `WRITE_EVENT` or both  \n\u003ecb : callback function that will be called by libel  \n\u003earg : it will be pass to callback function\n\n```c\nevent *el_sigevent_new(int signo, cb_func cb, void *arg) \n```\n\u003ecreate a new signal handler event. `signo` is the signal type, such as `SIGINT`.\n\n```c\nevent *el_timer(int timeout, cb_func cb, void *arg)\n```\n\u003ecreate a new timer event, `timeout`'s unit is millisecond.\n\n```c\nvoid el_event_add(el_loop *loop, event *e)\n```\n\u003eadd an event to a loop.\n\n```c\nint el_loop_run(el_loop *loop)\n```\n\u003e To start this event loop.\n\n```c\nvoid el_loop_free(el_loop *loop)\n```\n\u003efree event loop.\n\n```c\nvoid el_error(const char *msg)\n```\n\u003eprint msg, errno message and exit(-1).\n\n### example\n\n##### 1. An example of a simple server accept connection from many clients.\n\nserver  \n\n```c\n#include\u003clibel/el.h\u003e\n\n/**\ncreate a listener\n **/\nint create_listener() {\n  int listenfd;\n  struct sockaddr_in *servaddr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));\n  if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) \u003c 0)\n    el_error(\"socket error!\");\n  servaddr-\u003esin_family = AF_INET;\n  servaddr-\u003esin_port = htons(3333);\n  if (inet_pton(AF_INET, \"0.0.0.0\", \u0026servaddr-\u003esin_addr) \u003c 0)\n    el_error(\"inet_pton error!\");\n  if (bind(listenfd, (struct sockaddr *)servaddr, sizeof(struct sockaddr_in)) \u003c 0)\n    el_error(\"bind error!\");\n  if (listen(listenfd, LISTENQ) \u003c 0)\n    el_error(\"listen error!\");\n  return listenfd;\n}\n\n/**\n\t处理客户端发送过来的数据，打印数据。\n*/\nvoid onread(int fd, int size, void *arg) {\n  el_loop *loop = (el_loop*)arg;\n  char buf[MAXLINE];\n  int n;\n  while ((n = read(fd, buf, MAXLINE)) \u003e 0) {\n    buf[n] = '\\0';\n    printf(\"%s\", buf);\n  }\n  if (n == 0) {\n  //客户端已经完成数据的发送。关闭连接。\n    close(fd);\n  } else if (n \u003c 0) {\n    if (errno == EWOULDBLOCK || errno == EAGAIN) {\n    //如果客户端未发送数据完成，需要继续监听\n      event *e = el_event_new(fd, READ_EVENT, onread, loop);\n      el_event_add(loop, e);\n      return;\n    } else\n      el_error(\"read from connected socket error!\");\n  }\n}\n\n/*\n\t处理客户端发起连接的回调函数\n*/\nvoid onaccept(int fd, int size, void *arg) {\n  el_loop *loop = (el_loop*)arg;\n  int i;\n  //size 为缓冲区中的字节数\n  for (i = 0; i \u003c size; i++) {\n    int connfd;\n    if (( connfd = accept(fd, NULL, NULL)) \u003c 0) {\n      if (errno == EWOULDBLOCK || errno == ECONNABORTED\n\t  || errno == EINTR || errno == EPROTO) {\n\tcontinue;\n      } else\n\tel_error(\"accept error!\");\n    }\n    /**\n    \t将新建立的连接新建为事件，并加入loop。回调函数为onread。\n    */\n    event *e = el_event_new(connfd, READ_EVENT, onread, loop);\n    el_event_add(loop, e);\n    /**\n    \t在libel的处理机制中，每次事件触发并处理完成后，都会从loop中删除，\n    \t所以需要重新创建，并加入loop\n    */\n    event *old = el_event_new(fd, READ_EVENT, onaccept, loop);\n    el_event_add(loop, old);\n  }\n}\n\nint main() {\n  //创建监听\n  int listenfd = create_listener();\n  //新建loop\n  el_loop *loop = el_loop_new();\n  //新建要监听的事件，回调函数为 onaccept\n  event *e = el_event_new(listenfd, READ_EVENT, onaccept, loop);\n  //将要监听的事件注册到loop上\n  el_event_add(loop, e);\n  //启动loop\n  return el_loop_run(loop);\n}\n```\n\nclient\n\n```c\n#include\u003cstdio.h\u003e\n#include\u003cstdlib.h\u003e\n#include\u003csys/types.h\u003e\n#include\u003csys/socket.h\u003e\n#include\u003csys/time.h\u003e\n#include\u003carpa/inet.h\u003e\n#include\u003cerrno.h\u003e\n#include\u003cstring.h\u003e\n#define MAX 1024\n\nint main() {\n  int sockfd;\n  struct sockaddr_in servaddr;\n  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) \u003c 0) {\n    fprintf(stderr, \"socket error!\\n\");\n    exit(-1);\n  }\n  servaddr.sin_family = AF_INET;\n  servaddr.sin_port = htons(3333);\n  if (inet_pton(AF_INET, \"0.0.0.0\", \u0026servaddr.sin_addr) \u003c 0) {\n    fprintf(stderr, \"inet_pton error!\\n\");\n    exit(-1);\n  }\n  if (connect(sockfd, (struct sockaddr*) \u0026servaddr, sizeof(servaddr)) \u003c 0) {\n    fprintf(stderr, \"connect error!\\n\");\n    exit(-1);\n  }\n  char buf[MAX];\n  /**\n  \t客户端从终端接收数据，并向服务器端发送。\n  */\n  while (fgets(buf, MAX, stdin) != NULL) {\n    if (write(sockfd, buf, strlen(buf)) \u003c 0) {\n      fprintf(stderr, \"write error!\\n\");\n      exit(-1);\n    }\n  }\n  close(sockfd);\n  return 0;\n}\n\n```\n\n##### 2. an example of signal handler\n\n```c\n#include\u003clibel/el.h\u003e\n\nvoid cb(int fd, int size, void *arg) {\n  printf(\"sigint\\n\");\n}\n\nvoid cb2(int fd, int size, void *arg) {\n  printf(\"sigquit\\n\");\n}\n\nint main() {\n  el_loop *loop = el_loop_new();\n  //创建信号处理函数，处理信号SIGINT\n  event *e = el_sigevent_new(SIGINT, cb, NULL);\n  el_event_add(loop, e);\n  //创建信号处理函数，处理信号SIGQUIT\n  event *e2 = el_sigevent_new(SIGQUIT, cb2, NULL);\n  el_event_add(loop, e2);\n  return el_loop_run(loop);\n}\n\n```\n\n##### 3. an example of timer\n\n```c\n#include\u003clibel/el.h\u003e\n\nint tt;\n\nvoid cb(int fd, int size, void *arg) {\n  el_loop *loop = (el_loop*) arg;\n  printf(\"%d\\n\", tt++);\n  //如果想要定时器继续，同样需要重新建立\n  event *e = el_timer(3000, cb, loop);\n  el_event_add(loop, e);\n}\n\nvoid cb2(int fd, int size, void *arg) {\n  printf(\"sigint\\n\");\n}\n\nint main() {\n  el_loop *loop = el_loop_new();\n  //创建定时事件，时间间隔为3000ms\n  event *e = el_timer(3000, cb, loop);\n  el_event_add(loop, e);\n  //创建信号处理事件，处理信号SIGINT\n  event *e2 = el_sigevent_new(SIGINT, cb2, NULL);\n  el_event_add(loop, e2);\n  return el_loop_run(loop);\n}\n\n```\n\n### Todo\n`support more system`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluohaha%2Flibel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fluohaha%2Flibel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluohaha%2Flibel/lists"}