请选择 进入手机版 | 继续访问电脑版
开启辅助访问
QQ登录|微信登录|登录 |立即注册

盖茨网区块链技术社区

基于libevent的基本用法

==============创建一个event_base==================
函数声明在<event2/event.h>
struct event_base* base = event_base_new();
重新初始化
int event_reinit(struct event_base *base);

=============检查event_base的后端方法==============
有时候需要检查event_base支持哪些特征,或者当前使用哪种方法
const char **event_get_supported_methods(void);
event_get_supported_methods()函数返回一个指针
指向libevent支持的方法名字数组。这个数组的最后一个元素是NULL
eg:

  1. int i;
  2. const char **methods = event_get_supported_methods();
  3. printf("Starting Libevent %s.  Available methods are:\n",
  4.     event_get_version());
  5. for (i=0; methods[i] != NULL; ++i) {
  6.     printf("    %s\n", methods[i]);
  7. }
复制代码

================释放event_base=================
使用完event_base之后,使用event_base_free()进行释放。
接口

  1. void event_base_free(struct event_base *base);
复制代码

================1 运行事件循环=================
一旦有了一个已经注册了某些事件的event_base(关于如何创建和注册事件请看下一节),就需要让libevent等待事件并且通知事件的发生。
接口(1)为单独一个事件循环
  1. int event_base_loop(struct event_base *base, int flags);
复制代码
接口(2)为所有事件循环
  1. int event_base_dispatch(struct event_base *base);
复制代码

================2 停止事件循环=================
如果想在移除所有已注册的事件之前停止活动的事件循环,可以调用两个稍有不同的函数。
  1. int event_base_loopexit(struct event_base *base,
  2.                         const struct timeval *tv);
  3. int event_base_loopbreak(struct event_base *base);
复制代码
================ 创建事件 =================
  1. #define EV_TIMEOUT      0x01
  2. #define EV_READ         0x02
  3. #define EV_WRITE        0x04
  4. #define EV_SIGNAL       0x08
  5. #define EV_PERSIST      0x10
  6. #define EV_ET           0x20

  7. typedef evutil_socket_t int
  8. typedef void (*event_callback_fn)(evutil_socket_t, short, void *);

  9. struct event *event_new(struct event_base *base, evutil_socket_t fd,
  10.     short what, event_callback_fn cb,
  11.     void *arg);

  12. void event_free(struct event *event);
复制代码
what 参数是上述标志的集合
如果fd非负,则它是将被观察其读写事件的文件
事件被激活时,libevent将调用cb函数,传递这些参数:文件描述符fd,表示所有被触发事件的位字段,以及构造事件时的arg参数。

================ 添加事件 =================
接口(1)栈内存的添加
  1. event_add(struct event *, struct timeval*);
复制代码

接口(2)堆内存添加,有时event的相关cb和base会写在自己定义的结构体中用堆分配空间,则使用下面方法注册效率更高
  1. int event_assign(struct event *event, struct event_base *base,
复制代码
-----------------------------------------------------------------------
eg:
  1. #include <event2/event.h>

  2. void cb_func(evutil_socket_t fd, short what, void *arg)
  3. {
  4.         const char *data = arg;
  5.         printf("Got an event on socket %d:%s%s%s%s [%s]",
  6.             (int) fd,
  7.             (what&EV_TIMEOUT) ? " timeout" : "",
  8.             (what&EV_READ)    ? " read" : "",
  9.             (what&EV_WRITE)   ? " write" : "",
  10.             (what&EV_SIGNAL)  ? " signal" : "",
  11.             data);
  12. }

  13. void main_loop(evutil_socket_t fd1, evutil_socket_t fd2)
  14. {
  15.         struct event *ev1, *ev2;
  16.         struct timeval five_seconds = {5,0};
  17.         struct event_base *base = event_base_new();

  18.         /* The caller has already set up fd1, fd2 somehow, and make them
  19.            nonblocking. */

  20.         ev1 = event_new(base, fd1, EV_TIMEOUT|EV_READ|EV_PERSIST, cb_func,
  21.            (char*)"Reading event");
  22.         ev2 = event_new(base, fd2, EV_WRITE|EV_PERSIST, cb_func,
  23.            (char*)"Writing event");

  24.         event_add(ev1, &five_seconds);
  25.         event_add(ev2, NULL);
  26.         event_base_dispatch(base);
  27. }
复制代码
-----------------------------------------------------------------------

================ 带优先级的事件 =================
  1. int event_priority_set(struct event *event, int priority);
复制代码
多个不同优先级的事件同时成为激活的时候,低优先级的事件不会运行。libevent会执行高优先级的事件

================ 检查事件状态 =================
有时候需要了解事件是否已经添加,检查事件代表什么。
  1. int event_pending(const struct event *ev, short what, struct timeval *tv_out);
复制代码

event_pending()函数确定给定的事件是否是未决的或者激活的。
如果是,而且what参数设置了EV_READ、EV_WRITE、EV_SIGNAL或者EV_TIMEOUT等标志,则函数会返回事件当前为之未决或者激活的所有标志。
如果提供了tv_out参数,并且what参数中设置了EV_TIMEOUT标志,而事件当前正因超时事件而未决或者激活,则tv_out会返回事件的超时值。

==================TCP相关接口=======================
evutil_make_listen_socket_reuseable(evutil_socket_t)端口复用
evutil_make_socket_nonblocking(listener);设置非阻塞模式
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);用于管理连接套接字和base,
可以方便的与套接字读写,内置读写回调。
bufferevent_setcb(struct bufferevent *, read_cb, NULL, error_cb, void *); 设置bufferevent读写错误回调,arg为参数
void read_cb(struct bufferevent *bev, void *arg)回调函数类型
bufferevent_read(struct bufferevent *, char*, int)从bufferevent中读取数据
bufferevent_write(struct bufferevent *, char*, int);写数据

eg:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <errno.h>  
  4. #include <assert.h>  
  5. #include <arpa/inet.h>
  6. #include <sys/types.h>          /* See NOTES */
  7. #include <sys/socket.h>
  8.   
  9. #include <event2/event.h>  
  10. #include <event2/bufferevent.h>

  11. void read_cb(struct bufferevent *bev, void *arg)
  12. {
  13.         char buff[100] = {0};
  14.         int n = 0;
  15.         while(n = bufferevent_read(bev, buff, 100), n > 0)
  16.         {
  17.                 printf("rev:%s len:%d\n", buff, n);
  18.                 bufferevent_write(bev, buff, n);
  19.         }
  20. }

  21. void error_cb(struct bufferevent *bev, short what, void *arg)
  22. {
  23.         char buff[100] = {0};
  24.         int n = 0;
  25.         while(n = bufferevent_read(bev, buff, 100), n > 0)
  26.         {
  27.                 printf("%s len:%d\n", buff, n);
  28.         }
  29. }

  30. void do_accept(evutil_socket_t listener, short what, void *arg)
  31. {
  32.         struct event_base* base = (struct event_base*)arg;
  33.         struct sockaddr_in sin;
  34.         socklen_t len;
  35.         evutil_socket_t fd = accept(listener, (struct sockaddr *)&sin, &len);
  36.         struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  37.         bufferevent_setcb(bev, read_cb, NULL, error_cb, arg);  
  38.     bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST);
  39. }

  40. int main()
  41. {
  42.         evutil_socket_t listener = socket(AF_INET, SOCK_STREAM, 0);
  43.         if(listener <= 0)
  44.         {
  45.                 perror("listener");
  46.         }
  47.         evutil_make_listen_socket_reuseable(listener);
  48.        
  49.         struct sockaddr_in sin;
  50.         sin.sin_family = AF_INET;
  51.         sin.sin_port = htons(8000);
  52.         sin.sin_addr.s_addr = inet_addr("192.168.17.128");
  53.         bind(listener, (struct sockaddr *)&sin, sizeof(sin));
  54.        
  55.         listen(listener, 5);
  56.        
  57.         evutil_make_socket_nonblocking(listener);
  58.        
  59.         struct event_base* base = event_base_new();
  60.         struct event* event_tcp = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);
  61.         event_add(event_tcp, NULL);
  62.         event_base_dispatch(base);
  63.         return 0;
  64. }
复制代码
=============================构建http服务器================================
  1. struct evhttp * evhttp_new(struct event_base *base);创建一个httpevent
  2. evhttp_accept_socket(http, fd);接受HTTP请求,FD必须绑定监听
  3. evhttp_set_gencb(http, http_cb, NULL);设置回掉处理
  4. evhttp_set_cb(http, "/tang", http_cb, NULL);为指定路径设置回掉
  5. void http_cb(struct evhttp_request *req, void *arg)回掉函数格式
  6. const char *buff = evhttp_request_get_uri(req);得到输入路径
  7. struct evbuffer *buf = evbuffer_new();  创建一个用于数据流的buf
  8. evhttp_send_reply(req, 200, "OK", buf); 发生响应
复制代码
--------------------------------------------------------------------------
//解析URI的参数(即GET方法的参数)
  1. char *evhttp_decode_uri(const char *uri);解析url中‘?’后的参数字符串
  2. struct evkeyvalq params;键值对参数
  3. evhttp_parse_query(decoded_uri, ¶ms);从url解析键值对
  4. char* evhttp_find_header(struct evkeyvalq *, char *);从params中获得特定参数
复制代码

//解析URI的参数(即POST方法的参数)
  1. char * post_data = (char *) EVBUFFER_DATA(ev_req->input_buffer);得到参数字符串
  2. in t bufsize = EVBUFFER_LENGTH(ev_req->input_buffer);得到参数字符串大小
  3. char * tmp = (char *)malloc(bufsize + 5);将字符串拼接为url格式
  4. tmp[0] = ‘/’; tmp[1] = ‘?’;
  5. strncpy((char *) &tmp[2], post_data, bufsize);
  6. tmp[bufsize + 2] = 0;
  7. tmp[bufsize + 3] = 0;
  8. decoded_uri = evhttp_decode_uri(tmp);再和get一样的方法解析数据
复制代码

eg:
  1. #include <errno.h>  
  2. #include <string.h>  
  3. #include <fcntl.h>  
  4. #include <arpa/inet.h>
  5. #include <sys/types.h>          /* See NOTES */
  6. #include <sys/socket.h>
  7. #include <event2/event.h>  
  8. #include <event2/http.h>  
  9. #include <event2/buffer.h>

  10. void http_cb(struct evhttp_request *req, void *arg)
  11. {
  12.         printf("tang\n");
  13.         struct evbuffer *buf = evbuffer_new();  
  14.     if (buf == NULL)   
  15.     {  
  16.         printf("evbuffer_new error !\n");  
  17.         return;  
  18.     }  
  19.        
  20.         const char *buff = evhttp_request_get_uri(req);
  21.        
  22.         evbuffer_add_printf(buf,"<html>\n"  
  23.             "<head>\n"  
  24.             "  <title>Libevnet Test</title>\n"            
  25.             "</head>\n"  
  26.             "<body>\n"  
  27.             "  <h1>Hello world ,This is a Libenvet Test !</h1>\n"            
  28.             "</body>\n"  
  29.             "</html>\n%s\n", buff);  
  30.     evhttp_send_reply(req, 200, "OK", buf);   
  31. }

  32. int main()
  33. {
  34.         evutil_socket_t fd = socket(AF_INET, SOCK_STREAM, 0);
  35.        
  36.         evutil_make_listen_socket_reuseable(fd);
  37.         struct sockaddr_in sin;
  38.         sin.sin_family = AF_INET;
  39.         sin.sin_port = htons(8000);
  40.         sin.sin_addr.s_addr = inet_addr("192.168.17.128");
  41.         bind(fd, (struct sockaddr *)&sin, sizeof(sin));
  42.         listen(fd, 5);
  43.        
  44.         evutil_make_socket_nonblocking(fd);
  45.        
  46.         struct event_base* base = event_base_new();
  47.         struct evhttp *http = evhttp_new(base);
  48.         evhttp_accept_socket(http, fd);
  49.        
  50.         evhttp_set_gencb(http, http_cb, NULL);
  51.        
  52.         event_base_dispatch(base);  
  53.         return 0;
  54. }
复制代码


0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则