libevnet学习

http://blog.csdn.net/xuqianghit/article/details/6640920

libevnet学习笔记1



1.   Libevent是什么?

Libevent是一个轻量级的开源的高性能的网络库,被众多的开源项目使用,例如大名鼎鼎的memcached等。具有如下的显著的特点:事件驱动,轻量级(和ACE相比的话),跨平台,支持多路的IO复用技术,支持定时器、信号等事件。

2.   Libevent功能

Libevent提供了事件通知,io缓存事件,定时器,超时,异步解析dns,事件驱动的http server以及一个rpc框架。

事件通知:当文件描述符可读可写时将执行回调函数。

Io缓存:缓存事件提供了输入输出缓存,能自动的读入和写入,用户不必直接操作io。

定时器:libevent提供了定时器的机制,能够在一定的时间间隔之后调用回调函数。

异步的dns解析:libevent提供了异步解析dns服务器的dns解析函数集。

事件驱动的http服务器:libevent提供了一个简单的,可集成到应用程序中的HTTP服务器。

RPC客户端服务器框架:libevent为创建RPC服务器和客户端创建了一个RPC框架,能自动的封装和解封数据结构。

3.   Reactor模式

libevent是一个典型的reactor模式的实现。这里需要说明一个什么是reactor模式。普通的函数调用机制如下:程序调用某个函数,函数执行,程序等待,函数将结果返回给调用程序(如果含有函数返回值的话)。Reactor模式的基本流程如下:应用程序需要提供相应的接口并且注册到reactor上,如果相应的事件发生的话,那么reactor将自动调用相应的注册的接口函数(类似于.net中的回调函数)。

4.   Libevent安装

Libevent安装比较简单,安装过程如下(ubuntu下,其他系统下类似,libevent的版本2.0.12-stable ):
xuqiang@ubuntu:~/libevent/libevent-2.0.12-stable$ ./configure
xuqiang@ubuntu:~/libevent/libevent-2.0.12-stable$ make
xuqiang@ubuntu:~/libevent/libevent-2.0.12-stable$ sudo make install

5. 几个简单的示例程序

定时器:

[cpp]  view plain copy
  1. /* 
  2.  * XXX This sample code was once meant to show how to use the basic Libevent 
  3.  * interfaces, but it never worked on non-Unix platforms, and some of the 
  4.  * interfaces have changed since it was first written.  It should probably 
  5.  * be removed or replaced with something better. 
  6.  * 
  7.  * Compile with: 
  8.  * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent 
  9.  */  
  10.   
  11. #include <sys/types.h>  
  12.   
  13. #include <event2/event-config.h>  
  14.   
  15. #include <sys/stat.h>  
  16. #include <time.h>  
  17. #include <sys/time.h>  
  18. #include <fcntl.h>  
  19. #include <stdlib.h>  
  20. #include <stdio.h>  
  21. #include <string.h>  
  22. #include <errno.h>  
  23.   
  24. #include <event2/event.h>  
  25. #include <event2/event_struct.h>  
  26. #include <event2/util.h>  
  27.   
  28.   
  29.   
  30. struct timeval lasttime;  
  31.   
  32. int event_is_persistent;  
  33.   
  34. static void timeout_cb(evutil_socket_t fd, short event, void *arg)  
  35. {  
  36.     struct timeval newtime, difference;  
  37.     /* 这里是如何使用参数的 */  
  38.     struct event *timeout = arg;  
  39.     double elapsed;  
  40.   
  41.     evutil_gettimeofday(&newtime, NULL);  
  42.     evutil_timersub(&newtime, &lasttime, &difference);  
  43.     elapsed = difference.tv_sec +  
  44.         (difference.tv_usec / 1.0e6);  
  45.   
  46.     printf("timeout_cb called at %d: %.3f seconds elapsed.\n",  
  47.         (int)newtime.tv_sec, elapsed);  
  48.     lasttime = newtime;  
  49.   
  50.     if (! event_is_persistent) {  
  51.         struct timeval tv;  
  52.         evutil_timerclear(&tv);  
  53.         tv.tv_sec = 2;  
  54.         event_add(timeout, &tv);  
  55.     }  
  56. }  
  57.   
  58. int main(int argc, char **argv)  
  59. {  
  60.     struct event timeout;  
  61.     struct timeval tv;  
  62.     struct event_base *base;  
  63.     int flags;  
  64.   
  65.   
  66.     if (argc == 2 && !strcmp(argv[1], "-p")) {  
  67.         event_is_persistent = 1;  
  68.         flags = EV_PERSIST;  
  69.     } else {  
  70.         event_is_persistent = 0;  
  71.         flags = 0;  
  72.     }  
  73.   
  74.     /* Initalize the event library初始化程序库 */  
  75.     base = event_base_new();  
  76.   
  77.     /* Initalize one event,初始化一个event,注意在这里如何传递参数的 */  
  78.     event_assign(&timeout, base, -1, flags, timeout_cb, (void*) &timeout);  
  79.   
  80.     evutil_timerclear(&tv);  
  81.     tv.tv_sec = 2;  
  82.     /* 添加一个event */  
  83.     event_add(&timeout, &tv);  
  84.   
  85.     evutil_gettimeofday(&lasttime, NULL);  
  86.   
  87.     /* 开始运行 */  
  88.     event_base_dispatch(base);  
  89.   
  90.     return (0);  
  91. }  
信号量:

[cpp]  view plain copy
  1. /* 
  2.  * Compile with: 
  3.  * cc -I/usr/local/include -o signal-test \ 
  4.  *   signal-test.c -L/usr/local/lib -levent 
  5.     1. libevent头文件的使用? 
  6.     简单的应用中仅仅需要包含头文件<event.h>即可, 
  7.     在头文件<event.h>中仅仅是包含了另外的头文件 
  8.     2. 何时调用函数event_base_free? 
  9.     如果event_base不在使用的情况下,调用event_base_free 
  10.     删除event_base对象 
  11.  */  
  12.   
  13. #include <sys/types.h>  
  14.   
  15. #include <sys/stat.h>  
  16.   
  17. #include <sys/queue.h>  
  18. #include <unistd.h>  
  19. #include <sys/time.h>  
  20.   
  21.   
  22. #include <signal.h>  
  23. #include <fcntl.h>  
  24. #include <stdlib.h>  
  25. #include <stdio.h>  
  26. #include <string.h>  
  27. #include <errno.h>  
  28.   
  29. //  
  30. #include <event.h>  
  31.   
  32.   
  33. int called = 0;  
  34.   
  35. static void  
  36. signal_cb(evutil_socket_t fd, short event, void *arg)  
  37. {  
  38.     struct event *signal = arg;  
  39.   
  40.     printf("got signal.\n");  
  41.   
  42.     // 如果用户取消两次,这时删除改事件  
  43.     if (called >= 2)  
  44.         event_del(signal);  
  45.   
  46.     called++;  
  47. }  
  48.   
  49. int  
  50. main(int argc, char **argv)  
  51. {  
  52.     struct event signal_int;  
  53.     struct event_base* base;  
  54.   
  55.     /* Initalize the event library */  
  56.     base = event_base_new();  
  57.   
  58.     /* Initalize one event */  
  59.     event_assign(&signal_int, base, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,  
  60.         &signal_int);  
  61.   
  62.     event_add(&signal_int, NULL);  
  63.   
  64.     event_base_dispatch(base);  
  65.   
  66.     /* 
  67.         如果一个event_base对象不再使用的话,可以调用 
  68.         改函数删除event_base,但是这里需要注意的时event_base 
  69.         并不删除和event_base相关联的event对象,也不删除 
  70.         打开的其他资源 
  71.      */  
  72.     event_base_free(base);  
  73.   
  74.     return (0);  
  75. }  

io事件:

[cpp]  view plain copy
  1. #include <sys/types.h>  
  2. #include <sys/stat.h>  
  3. #include <sys/queue.h>  
  4. #include <unistd.h>  
  5. #include <sys/time.h>  
  6. #include <fcntl.h>  
  7. #include <stdlib.h>  
  8. #include <stdio.h>  
  9. #include <string.h>  
  10. #include <errno.h>  
  11.   
  12. #include <event.h>  
  13.   
  14. static void fifo_read(int fd, short event, void *arg)  
  15. {  
  16.     char buf[255];  
  17.     int len;  
  18.     struct event *ev = arg;  
  19.   
  20.   
  21.     /* Reschedule this event这里需要重新添加改事件 */  
  22.     event_add(ev, NULL);  
  23.   
  24.     fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n",  
  25.         fd, event, arg);  
  26.   
  27.     len = read(fd, buf, sizeof(buf) - 1);  
  28.   
  29.     if (len == -1) {  
  30.         perror("read");  
  31.         return;  
  32.     } else if (len == 0) {  
  33.         fprintf(stderr, "Connection closed\n");  
  34.         return;  
  35.     }  
  36.   
  37.     buf[len] = '\0';  
  38.   
  39.     fprintf(stdout, "Read: %s\n", buf);  
  40. }  
  41.   
  42. int main(int argc, char **argv)  
  43. {  
  44.     struct event evfifo;  
  45.     struct stat st;  
  46.     const char *fifo = "event.fifo";  
  47.     int socket;  
  48.   
  49.     if (lstat(fifo, &st) == 0) {  
  50.         if ((st.st_mode & S_IFMT) == S_IFREG) {  
  51.             errno = EEXIST;  
  52.             perror("lstat");  
  53.             exit(1);  
  54.         }  
  55.     }  
  56.   
  57.     unlink(fifo);  
  58.     if (mkfifo(fifo, 0600) == -1) {  
  59.         perror("mkfifo");  
  60.         exit(1);  
  61.     }  
  62.   
  63.     /* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */  
  64.     // 打开fifo  
  65.     socket = open(fifo, O_RDWR | O_NONBLOCK, 0);  
  66.   
  67.     if (socket == -1) {  
  68.         perror("open");  
  69.         exit(1);  
  70.     }  
  71.   
  72.     fprintf(stderr, "Write data to %s\n", fifo);  
  73.   
  74.     /* Initalize the event library初始化程序库 */  
  75.     event_init();  
  76.   
  77.     /* Initalize one event */  
  78.     /* 初始化event类型,注册回调函数fifo_read */  
  79.     event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);  
  80.   
  81.     /* Add it to the active events, without a timeout 
  82.         添加event 
  83.     */  
  84.     event_add(&evfifo, NULL);  
  85.   
  86.     /* 
  87.         开始调度“event” 
  88.     */  
  89.     event_dispatch();  
  90.   
  91.   
  92.     return (0);  
  93. }  

bufferevent使用:

[cpp]  view plain copy
  1. /* 
  2.  * libevent echo server example using buffered events. 
  3.  */  
  4.   
  5. #include <sys/types.h>  
  6. #include <sys/socket.h>  
  7. #include <netinet/in.h>  
  8. #include <arpa/inet.h>  
  9.   
  10. /* Required by event.h. */  
  11. #include <sys/time.h>  
  12.   
  13. #include <stdlib.h>  
  14. #include <stdio.h>  
  15. #include <string.h>  
  16. #include <fcntl.h>  
  17. #include <unistd.h>  
  18. #include <errno.h>  
  19. #include <err.h>  
  20.   
  21. /* Libevent. */  
  22. #include <event.h>  
  23.   
  24. /* Port to listen on. */  
  25. #define SERVER_PORT 5555  
  26.   
  27. /** 
  28.  * A struct for client specific data, also includes pointer to create 
  29.  * a list of clients. 
  30.  */  
  31. struct client {  
  32.     /* The clients socket. */  
  33.     int fd;  
  34.   
  35.     /* The bufferedevent for this client. */  
  36.     struct bufferevent *buf_ev;  
  37. };  
  38.   
  39. /** 
  40.  * Set a socket to non-blocking mode. 
  41.  */  
  42. int  
  43. setnonblock(int fd)  
  44. {  
  45.     int flags;  
  46.   
  47.     flags = fcntl(fd, F_GETFL);  
  48.     if (flags < 0)  
  49.         return flags;  
  50.     flags |= O_NONBLOCK;  
  51.     if (fcntl(fd, F_SETFL, flags) < 0)  
  52.         return -1;  
  53.   
  54.     return 0;  
  55. }  
  56.   
  57. /** 
  58.  * Called by libevent when there is data to read. 
  59.  */  
  60. void  
  61. buffered_on_read(struct bufferevent *bev, void *arg)  
  62. {  
  63.     /* Write back the read buffer. It is important to note that 
  64.      * bufferevent_write_buffer will drain the incoming data so it 
  65.      * is effectively gone after we call it. */  
  66.     bufferevent_write_buffer(bev, bev->input);  
  67. }  
  68.   
  69. /** 
  70.  * Called by libevent when the write buffer reaches 0.  We only 
  71.  * provide this because libevent expects it, but we don't use it. 
  72.  */  
  73. void  
  74. buffered_on_write(struct bufferevent *bev, void *arg)  
  75. {  
  76. }  
  77.   
  78. /** 
  79.  * Called by libevent when there is an error on the underlying socket 
  80.  * descriptor. 
  81.  */  
  82. void  
  83. buffered_on_error(struct bufferevent *bev, short what, void *arg)  
  84. {  
  85.     struct client *client = (struct client *)arg;  
  86.   
  87.     if (what & EVBUFFER_EOF) {  
  88.         /* Client disconnected, remove the read event and the 
  89.          * free the client structure. */  
  90.         printf("Client disconnected.\n");  
  91.     }  
  92.     else {  
  93.         warn("Client socket error, disconnecting.\n");  
  94.     }  
  95.     bufferevent_free(client->buf_ev);  
  96.     close(client->fd);  
  97.     free(client);  
  98. }  
  99.   
  100. /** 
  101.  * This function will be called by libevent when there is a connection 
  102.  * ready to be accepted. 
  103.  */  
  104. void  
  105. on_accept(int fd, short ev, void *arg)  
  106. {  
  107.     int client_fd;  
  108.     struct sockaddr_in client_addr;  
  109.     socklen_t client_len = sizeof(client_addr);  
  110.     struct client *client;  
  111.   
  112.     client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);  
  113.     if (client_fd < 0) {  
  114.         warn("accept failed");  
  115.         return;  
  116.     }  
  117.   
  118.     /* Set the client socket to non-blocking mode. */  
  119.     if (setnonblock(client_fd) < 0)  
  120.         warn("failed to set client socket non-blocking");  
  121.   
  122.     /* We've accepted a new client, create a client object. */  
  123.     client = calloc(1, sizeof(*client));  
  124.     if (client == NULL)  
  125.         err(1, "malloc failed");  
  126.     client->fd = client_fd;  
  127.       
  128.     /* Create the buffered event. 
  129.      * 
  130.      * The first argument is the file descriptor that will trigger 
  131.      * the events, in this case the clients socket. 
  132.      * 
  133.      * The second argument is the callback that will be called 
  134.      * when data has been read from the socket and is available to 
  135.      * the application. 
  136.      * 
  137.      * The third argument is a callback to a function that will be 
  138.      * called when the write buffer has reached a low watermark. 
  139.      * That usually means that when the write buffer is 0 length, 
  140.      * this callback will be called.  It must be defined, but you 
  141.      * don't actually have to do anything in this callback. 
  142.      * 
  143.      * The fourth argument is a callback that will be called when 
  144.      * there is a socket error.  This is where you will detect 
  145.      * that the client disconnected or other socket errors. 
  146.      * 
  147.      * The fifth and final argument is to store an argument in 
  148.      * that will be passed to the callbacks.  We store the client 
  149.      * object here. 
  150.      */  
  151.     client->buf_ev = bufferevent_new(client_fd, buffered_on_read,  
  152.         buffered_on_write, buffered_on_error, client);  
  153.   
  154.     /* We have to enable it before our callbacks will be 
  155.      * called. */  
  156.     bufferevent_enable(client->buf_ev, EV_READ);  
  157.   
  158.     printf("Accepted connection from %s\n",   
  159.         inet_ntoa(client_addr.sin_addr));  
  160. }  
  161.   
  162. int  
  163. main(int argc, char **argv)  
  164. {  
  165.     int listen_fd;  
  166.     struct sockaddr_in listen_addr;  
  167.     struct event ev_accept;  
  168.     int reuseaddr_on;  
  169.   
  170.     /* Initialize libevent. */  
  171.     event_init();  
  172.   
  173.     /* Create our listening socket. */  
  174.     listen_fd = socket(AF_INET, SOCK_STREAM, 0);  
  175.     if (listen_fd < 0)  
  176.         err(1, "listen failed");  
  177.     memset(&listen_addr, 0, sizeof(listen_addr));  
  178.     listen_addr.sin_family = AF_INET;  
  179.     listen_addr.sin_addr.s_addr = INADDR_ANY;  
  180.     listen_addr.sin_port = htons(SERVER_PORT);  
  181.     if (bind(listen_fd, (struct sockaddr *)&listen_addr,  
  182.         sizeof(listen_addr)) < 0)  
  183.         err(1, "bind failed");  
  184.     if (listen(listen_fd, 5) < 0)  
  185.         err(1, "listen failed");  
  186.     reuseaddr_on = 1;  
  187.     setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on,   
  188.         sizeof(reuseaddr_on));  
  189.   
  190.     /* Set the socket to non-blocking, this is essential in event 
  191.      * based programming with libevent. */  
  192.     if (setnonblock(listen_fd) < 0)  
  193.         err(1, "failed to set server socket to non-blocking");  
  194.   
  195.     /* We now have a listening socket, we create a read event to 
  196.      * be notified when a client connects. */  
  197.     event_set(&ev_accept, listen_fd, EV_READ|EV_PERSIST, on_accept, NULL);  
  198.     event_add(&ev_accept, NULL);  
  199.   
  200.     /* Start the event loop. */  
  201.     event_dispatch();  
  202.   
  203.     return 0;  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值