当前位置:   article > 正文

Linux网络编程:libevent事件通知I/O框架_libevent框架

libevent框架

文章目录:

一:libevent库

二:libevent框架

1.常规事件event

1.1 创建事件event(event_new) 

1.2 添加事件到 event_base(event_add) 

1.3 从event_base上摘下事件(event_del)

1.4 销毁事件(event_free)

1.5 未决和非未决

read_fifo.c

write_fifo.c

2.带缓冲区的事件bufferevent

2.1 带缓冲区的事件 bufferevent

2.2 创建、销毁bufferevent(bufferevent_socket_new 、bufferevent_socket_free)

2.3 给bufferevent设置回调(bufferevent_setcb)

2.4 启动、关闭 bufferevent的 缓冲区(bufferevent_enable、bufferevnet_disable)

三:网络通信 

1.服务端

1.1 创建和释放监听服务器(evconnlistener_new_bind、evconnlistener_free) 

1.2 服务器端 libevent 创建TCP连接流程

ev_server.c

2.客户端

2.1 连接客户端(bufferevent_socket_connect) 

2.2 Libevent实现TCP客户端流程 

ev_client.c


一:libevent库

libevent官网: 底层封装了select,poll,epoll便于使用

  1. libevent库
  2. 开源;精简;跨平台(Windows、Linux、maxos、unix);专注于网络通信
  3. 源码包安装: 参考 README、readme
  4. ./configure 检查安装环境 生成 makefile
  5. make 生成 .o 和 可执行文件
  6. sudo make install 将必要的资源cp置系统指定目录
  7. 进入 sample 目录,运行demo验证库安装使用情况
  8. 编译使用库的 .c 时,需要加 -levent 选项
  9. 库名 libevent.so --> /usr/local/lib 查看的到
  10. 特性:
  11. 基于“事件”异步通信模型。--- 回调

二:libevent框架

  1. libevent框架:
  2. 1. 创建 event_base (乐高底座)
  3. struct event_base *event_base_new(void);
  4. struct event_base *base = event_base_new();
  5. 2. 创建 事件evnet (积木)
  6. 常规事件 event --> event_new();
  7. 带缓冲区的事件 bufferevent --> bufferevent_socket_new();
  8. 3. 将事件 添加到 base
  9. int event_add(struct event *ev, const struct timeval *tv)
  10. 4. 循环监听事件满足
  11. int event_base_dispatch(struct event_base *base);
  12. event_base_dispatch(base);
  13. 5. 释放 event_base
  14. event_base_free(base);

1.常规事件event

1.1 创建事件event(event_new) 
  1. 创建事件event
  2. struct event *ev;
  3. struct event *event_new(struct event_base *base,evutil_socket_t fd,short what,event_callback_fn cb; void *arg);
  4. base: event_base_new()返回值
  5. fd: 绑定到 event 上的 文件描述符
  6. what:对应的事件(r、w、e)
  7. EV_READ 一次 读事件
  8. EV_WRTIE 一次 写事件
  9. EV_PERSIST 持续触发。 结合 event_base_dispatch 函数使用,生效
  10. cb:一旦事件满足监听条件,回调的函数
  11. typedef void (*event_callback_fn)(evutil_socket_t fd, short, void *)
  12. arg: 回调的函数的参数
  13. 返回值:成功创建的 event
1.2 添加事件到 event_base(event_add) 
  1. 添加事件到 event_base
  2. int event_add(struct event *ev, const struct timeval *tv);
  3. ev: event_new() 的返回值
  4. tv:NULL
1.3 从event_base上摘下事件(event_del)
  1. 从event_base上摘下事件 【了解】
  2. int event_del(struct event *ev);
  3. ev: event_new() 的返回值
1.4 销毁事件(event_free)
  1. 销毁事件
  2. int event_free(struct event *ev);
  3. ev: event_new() 的返回值
1.5 未决和非未决

  1. 未决和非未决:
  2. 非未决: 没有资格被处理
  3. 未 决:有资格被处理,但尚未被处理
  4. event_new --> event ---> 非未决 --> event_add --> 未决 --> dispatch() && 监听事件被触发 --> 激活态
  5. --> 执行回调函数 --> 处理态 --> 非未决 event_add && EV_PERSIST --> 未决 --> event_del --> 非未决

read_fifo.c

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #include <event2/event.h>
  9. // 对操作处理函数
  10. void read_cb(evutil_socket_t fd, short what, void *arg)
  11. {
  12. // 读管道
  13. char buf[1024] = {0};
  14. int len = read(fd, buf, sizeof(buf));
  15. printf("read event: %s \n", what & EV_READ ? "Yes" : "No");
  16. printf("data len = %d, buf = %s\n", len, buf);
  17. sleep(1);
  18. }
  19. // 读管道
  20. int main(int argc, const char* argv[])
  21. {
  22. unlink("myfifo");
  23. //创建有名管道
  24. mkfifo("myfifo", 0664);
  25. // open file
  26. //int fd = open("myfifo", O_RDONLY | O_NONBLOCK);
  27. int fd = open("myfifo", O_RDONLY);
  28. if(fd == -1)
  29. {
  30. perror("open error");
  31. exit(1);
  32. }
  33. // 创建个event_base
  34. struct event_base* base = NULL;
  35. base = event_base_new();
  36. // 创建事件
  37. struct event* ev = NULL;
  38. ev = event_new(base, fd, EV_READ | EV_PERSIST, read_cb, NULL);
  39. // 添加事件
  40. event_add(ev, NULL);
  41. // 事件循环
  42. event_base_dispatch(base); // while(1) { epoll();}
  43. // 释放资源
  44. event_free(ev);
  45. event_base_free(base);
  46. close(fd);
  47. return 0;
  48. }

write_fifo.c

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #include <event2/event.h>
  9. // 对操作处理函数
  10. void write_cb(evutil_socket_t fd, short what, void *arg)
  11. {
  12. // write管道
  13. char buf[1024] = {0};
  14. static int num = 0;
  15. sprintf(buf, "hello,world-%d\n", num++);
  16. write(fd, buf, strlen(buf)+1);
  17. sleep(1);
  18. }
  19. // 写管道
  20. int main(int argc, const char* argv[])
  21. {
  22. // open file
  23. //int fd = open("myfifo", O_WRONLY | O_NONBLOCK);
  24. int fd = open("myfifo", O_WRONLY);
  25. if(fd == -1)
  26. {
  27. perror("open error");
  28. exit(1);
  29. }
  30. // 写管道
  31. struct event_base* base = NULL;
  32. base = event_base_new();
  33. // 创建事件
  34. struct event* ev = NULL;
  35. // 检测的写缓冲区是否有空间写
  36. //ev = event_new(base, fd, EV_WRITE , write_cb, NULL);
  37. ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);
  38. // 添加事件
  39. event_add(ev, NULL);
  40. // 事件循环
  41. event_base_dispatch(base);
  42. // 释放资源
  43. event_free(ev);
  44. event_base_free(base);
  45. close(fd);
  46. return 0;
  47. }

2.带缓冲区的事件bufferevent

2.1 带缓冲区的事件 bufferevent

  1. 带缓冲区的事件 bufferevent
  2. #include <event2/bufferevent.h>
  3. read/write 两个缓冲. 借助 队列
  4. 原理: bufferent利用队列实现两个缓冲区(数据读走就没, FIFO);
  5. 读: 有数据, 读回调函数被调用, 使用bufferevent_read()读数据;
  6. 写: 使用bufferevent_write, 向写缓冲中写数据, 该缓冲区中有数据自动写出, 写完后, 回调函数被调用(鸡肋);

2.2 创建、销毁bufferevent(bufferevent_socket_new 、bufferevent_socket_free)

  1. 创建bufferevent:
  2. struct bufferevent* bufferevent_socket_new(struct event_base* base,
  3. evutil_socket_t fd,
  4. enum bfferevent_options options)
  5. base: 基事件, event_base_new函数的返回值;
  6. fd:封装到bufferevent内的fd(绑定在一起);
  7. enum表示枚举类型, 一般取BEV_OPT_CLOSE_ON_FREE;
  8. 成功返回bufferevent事件对象;
  9. 销毁bufferevent:
  10. void bufferevent_socket_free(struct bufferevent* ev)

2.3 给bufferevent设置回调(bufferevent_setcb)

  1. 给bufferevent设置回调:
  2. 对比event: event_new( fd, callback ); event_add() -- 挂到 event_base 上。
  3. bufferevent_socket_new(fd) bufferevent_setcb( callback )
  4. void bufferevent_setcb(struct bufferevent * bufev,
  5. bufferevent_data_cb readcb,
  6. bufferevent_data_cb writecb,
  7. bufferevent_event_cb eventcb,
  8. void *cbarg );
  9. bufev: bufferevent_socket_new() 返回值
  10. readcb: 设置 bufferevent 读缓冲,对应回调 read_cb{ bufferevent_read() 读数据 }
  11. writecb: 设置 bufferevent 写缓冲,对应回调 write_cb { } -- 给调用者,发送写成功通知。 可以 NULL
  12. eventcb: 可传NULL;
  13. cbarg: 回调函数的参数;
  14. eventcb: 设置 事件回调。 也可传NULL
  15. typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short events, void *ctx);
  16. void event_cb(struct bufferevent *bev, short events, void *ctx)
  17. {
  18. 。。。。。
  19. }
  20. events: BEV_EVENT_CONNECTED
  21. read 读回调函数类型(read_cb :bufferevent_read()):
  22. typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void*ctx);
  23. void read_cb(struct bufferevent *bev, void *cbarg )
  24. {
  25. .....
  26. bufferevent_read(); --- read();
  27. }
  28. bufferevent_read()函数的原型:
  29. size_t bufferevent_read(struct bufferevent *bev, void *buf, size_t bufsize);
  30. write 写回调函数类型(bufferevent_write):
  31. int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);

2.4 启动、关闭 bufferevent的 缓冲区(bufferevent_enable、bufferevnet_disable)

  1. 启动、关闭 bufferevent的 缓冲区:
  2. void bufferevent_enable(struct bufferevent* bufev,short events); //启用缓冲区
  3. void bufferevnet_disable(struct bufferevent* bufev,short events); //禁用
  4. events的值可传入三个宏: EV_READ、EV_WRITE、EV_READ|EV_WRITE
  5. 默认、write 缓冲是 enable、read 缓冲是 disable
  6. bufferevent_enable(evev, EV_READ); -- 开启读缓冲

三:网络通信 

1.服务端

1.1 创建和释放监听服务器(evconnlistener_new_bind、evconnlistener_free) 

  1. 创建监听服务器:
  2. ------ socket();bind();listen();accept();
  3. struct evconnlistener * listner
  4. //这一个函数可以完成`socket(),bind(),listen(),accept()`四个函数的作用
  5. struct evconnlistener *evconnlistener_new_bind (
  6. struct event_base *base,
  7. evconnlistener_cb cb,
  8. void *ptr,
  9. unsigned flags,
  10. int backlog,
  11. const struct sockaddr *sa,
  12. int socklen);
  13. base: event_base
  14. cb: 回调函数。 一旦被回调,说明在其内部应该与客户端完成, 数据读写操作,进行通信
  15. ptr: 回调函数的参数
  16. flags: LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE
  17. backlog: listen() 2参。 -1 表最大值
  18. sa:服务器自己的地址结构体
  19. socklen:服务器自己的地址结构体大小
  20. 返回值:成功创建的监听器
  21. //回调函数的类型
  22. typedef void (*evconnlistener_cb)(struct evconnlistener* listener,
  23. evutil_socker_t sock,
  24. struct sockaddr* addr,
  25. int len,
  26. void* ptr);
  27. listener:evconnlistener_new_bind函数的返回值;
  28. sock:用于通信的文件描述符;
  29. addr:客户端的地址结构;
  30. len:客户端地址结构的长度;
  31. ptr:外部ptr传进来的值;
  32. 释放监听服务器:
  33. void evconnlistener_free(struct evconnlistener *lev);

1.2 服务器端 libevent 创建TCP连接流程

  1. 服务器端 libevent 创建TCP连接:
  2. 1. 创建event_base
  3. 2. 创建bufferevent事件对象。bufferevent_socket_new()
  4. 3. 使用bufferevent_setcb() 函数给 bufferevent的 readwrite、event 设置回调函数
  5. 4. 当监听的 事件满足时,read_cb会被调用, 在其内部 bufferevent_read()读
  6. 5. 使用 evconnlistener_new_bind 创建监听服务器, 设置其回调函数,当有客户端成功连接时,这个回调函数会被调用
  7. 6. 封装 listner_cb() 在函数内部。完成与客户端通信
  8. 7. 设置读缓冲、写缓冲的 使能状态 enable、disable
  9. 8. 启动循环 event_base_dispath()
  10. 9. 释放连接
ev_server.c
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <string.h>
  7. #include <event2/event.h>
  8. #include <event2/listener.h>
  9. #include <event2/bufferevent.h>
  10. // 读缓冲区回调
  11. void read_cb(struct bufferevent *bev, void *arg)
  12. {
  13. char buf[1024] = {0};
  14. // 借助读缓冲,从客户端拿数据
  15. bufferevent_read(bev, buf, sizeof(buf));
  16. printf("client say: %s\n", buf);
  17. char *p = "我是服务器, 已经成功收到你发送的数据!";
  18. // 借助写缓冲,写数据回给客户端
  19. bufferevent_write(bev, p, strlen(p)+1);
  20. sleep(1);
  21. }
  22. // 写缓冲区回调
  23. void write_cb(struct bufferevent *bev, void *arg)
  24. {
  25. printf("I'm服务器, 成功写数据给客户端,写缓冲区回调函数被回调...\n");
  26. }
  27. // 事件
  28. void event_cb(struct bufferevent *bev, short events, void *arg)
  29. {
  30. if (events & BEV_EVENT_EOF)
  31. {
  32. printf("connection closed\n");
  33. }
  34. else if(events & BEV_EVENT_ERROR)
  35. {
  36. printf("some other error\n");
  37. }
  38. bufferevent_free(bev);
  39. printf("buffevent 资源已经被释放...\n");
  40. }
  41. // 被回调,说明有客户端成功连接, cfd已经传入该参数内部。 创建bufferevent事件对象
  42. //与客户端完成读写操作
  43. void cb_listener(
  44. struct evconnlistener *listener,
  45. evutil_socket_t fd,
  46. struct sockaddr *addr,
  47. int len, void *ptr)
  48. {
  49. printf("connect new client\n");
  50. struct event_base* base = (struct event_base*)ptr;
  51. // 通信操作
  52. // 创建添加新事件bufferevent 对象
  53. struct bufferevent *bev;
  54. bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  55. // 给bufferevent缓冲区设置回调 readwrite、event
  56. void bufferevent_setcb(struct bufferevent * bufev,
  57. bufferevent_data_cb readcb,
  58. bufferevent_data_cb writecb,
  59. bufferevent_event_cb eventcb,
  60. void *cbarg );
  61. //设置回调函数
  62. bufferevent_setcb(bev, read_cb, write_cb, event_cb,NULL,NULL);
  63. //启动 read 缓冲区的 使能状态
  64. bufferevent_enable(bev, EV_READ);
  65. }
  66. int main(int argc, const char* argv[])
  67. {
  68. // 定义服务器地址结构init server
  69. struct sockaddr_in serv;
  70. memset(&serv, 0, sizeof(serv));
  71. serv.sin_family = AF_INET;
  72. serv.sin_port = htons(9876);
  73. serv.sin_addr.s_addr = htonl(INADDR_ANY);
  74. // 创建event_base
  75. struct event_base* base;
  76. base = event_base_new();
  77. // 创建套接字
  78. // 绑定
  79. // 创建服务器监听器:接收连接请求
  80. struct evconnlistener* listener; //监听器
  81. listener = evconnlistener_new_bind(base, cb_listener, base,
  82. LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
  83. 36, (struct sockaddr*)&serv, sizeof(serv));
  84. //启动监听循环
  85. event_base_dispatch(base);
  86. //销毁event_base
  87. evconnlistener_free(listener);
  88. event_base_free(base);
  89. return 0;
  90. }

2.客户端

2.1 连接客户端(bufferevent_socket_connect) 

  1. 连接客户端:
  2. socket();connect();
  3. int bufferevent_socket_connect(struct bufferevent *bev, struct sockaddr *address, int addrlen);
  4. bev: bufferevent 事件对象(封装了fd
  5. address、len:等同于 connect() 参2/3

2.2 Libevent实现TCP客户端流程 

  1. Libevent实现TCP客户端流程
  2. 1.创建event_basev
  3. 2.使用bufferevnet_socket_new()创建一个用跟服务器通信的 bufferevnet事件对象
  4. 3.使用bufferevnet_socket_connect()连接服务器
  5. 4.使用bufferevent_setcb()给 bufferevnet对象的 readwrite、event设置回调
  6. 5.设置bufferevnet 对象的读写缓冲区enable / disable
  7. 6.接受、发送数据bufferevent_read() / bufferevent_write()
  8. 7.启动循环监听event_base_dispatch
  9. 8.释放资源
ev_client.c
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <string.h>
  7. #include <event2/bufferevent.h>
  8. #include <event2/event.h>
  9. #include <arpa/inet.h>
  10. void read_cb(struct bufferevent *bev, void *arg)
  11. {
  12. char buf[1024] = {0};
  13. bufferevent_read(bev, buf, sizeof(buf));
  14. printf("fwq say:%s\n", buf);
  15. bufferevent_write(bev, buf, strlen(buf)+1);
  16. sleep(1);
  17. }
  18. void write_cb(struct bufferevent *bev, void *arg)
  19. {
  20. printf("----------我是客户端的写回调函数,没卵用\n");
  21. }
  22. void event_cb(struct bufferevent *bev, short events, void *arg)
  23. {
  24. if (events & BEV_EVENT_EOF)
  25. {
  26. printf("connection closed\n");
  27. }
  28. else if(events & BEV_EVENT_ERROR)
  29. {
  30. printf("some other error\n");
  31. }
  32. else if(events & BEV_EVENT_CONNECTED)
  33. {
  34. printf("已经连接服务器...\\(^o^)/...\n");
  35. return;
  36. }
  37. // 释放资源
  38. bufferevent_free(bev);
  39. }
  40. // 客户端与用户交互,从终端读取数据写给服务器
  41. void read_terminal(evutil_socket_t fd, short what, void *arg)
  42. {
  43. // 读数据
  44. char buf[1024] = {0};
  45. int len = read(fd, buf, sizeof(buf));
  46. struct bufferevent* bev = (struct bufferevent*)arg;
  47. // 发送数据
  48. bufferevent_write(bev, buf, len+1);
  49. }
  50. int main(int argc, const char* argv[])
  51. {
  52. struct event_base* base = NULL;
  53. base = event_base_new();
  54. int fd = socket(AF_INET, SOCK_STREAM, 0);
  55. // 通信的fd放到bufferevent中
  56. struct bufferevent* bev = NULL;
  57. bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  58. // init server info
  59. struct sockaddr_in serv;
  60. memset(&serv, 0, sizeof(serv));
  61. serv.sin_family = AF_INET;
  62. serv.sin_port = htons(9876);
  63. inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
  64. // 连接服务器
  65. bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));
  66. // 设置回调
  67. bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
  68. // 设置读回调生效
  69. // bufferevent_enable(bev, EV_READ);
  70. // 创建事件
  71. struct event* ev = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST,
  72. read_terminal, bev);
  73. // 添加事件
  74. event_add(ev, NULL);
  75. event_base_dispatch(base);
  76. event_free(ev);
  77. event_base_free(base);
  78. return 0;
  79. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/561011
推荐阅读
相关标签
  

闽ICP备14008679号