7.4 使用bufferevent

基于套接字的 bufferevent 是最简单的,它使用 libevent 的底层事件机制来检测底层网络套 接字是否已经就绪,可以进行读写操作,并且使用底层网络调用(如 readv 、 writev 、 WSASend、WSARecv)来发送和接收数据。

7.4.1 创建基于套接字的bufferevent

可以使用 bufferevent_socket_new()创建基于套接字的 bufferevent。

  1. struct bufferevent *bufferevent_socket_new(
  2. struct event_base *base,
  3. evutil_socket_t fd,
  4. enum bufferevent_options options);

base 是 event_base,options 是表示 bufferevent 选项(BEV_OPT_CLOSE_ON_FREE 等) 的位掩码, fd是一个可选的表示套接字的文件描述符。如果想以后设置文件描述符,可以设置fd为-1。

成功时函数返回一个 bufferevent,失败则返回 NULL。

7.4.2 在bufferevent上启动链接

  1. int bufferevent_socket_connect(struct bufferevent *bev,
  2. struct sockaddr *address, int addrlen);

address 和 addrlen 参数跟标准调用 connect()的参数相同。如果还没有为 bufferevent 设置套接字,调用函数将为其分配一个新的流套接字,并且设置为非阻塞的。

如果已经为 bufferevent 设置套接字,调用bufferevent_socket_connect() 将告知 libevent 套接字还未连接,直到连接成功之前不应该对其进行读取或者写入操作。

连接完成之前可以向输出缓冲区添加数据。

如果连接成功启动,函数返回 0;如果发生错误则返回 -1。

  1. #include <event2/event.h>
  2. #include <event2/bufferevent.h>
  3. #include <sys/socket.h>
  4. #include <string.h>
  5. void eventcb(struct bufferevent *bev, short events, void *ptr)
  6. {
  7. if (events & BEV_EVENT_CONNECTED) {
  8. /* We're connected to 127.0.0.1:8080. Ordinarily we'd do
  9. something here, like start reading or writing. */
  10. } else if (events & BEV_EVENT_ERROR) {
  11. /* An error occured while connecting. */
  12. }
  13. }
  14. int main_loop(void)
  15. {
  16. struct event_base *base;
  17. struct bufferevent *bev;
  18. struct sockaddr_in sin;
  19. base = event_base_new();
  20. memset(&sin, 0, sizeof(sin));
  21. sin.sin_family = AF_INET;
  22. sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
  23. sin.sin_port = htons(8080); /* Port 8080 */
  24. bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
  25. bufferevent_setcb(bev, NULL, NULL, eventcb, NULL);
  26. if (bufferevent_socket_connect(bev,
  27. (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  28. /* Error starting connection */
  29. bufferevent_free(bev);
  30. return -1;
  31. }
  32. event_base_dispatch(base);
  33. return 0;
  34. }

注意:如果使用 bufferevent_socket_connect() 发起连接,将只会收 到 BEV_EVENT_CONNECTED 事件。如果自己调用 connect(),则连接上将被报告为写入事 件。