这段时间抽空学习了一下强大的网络库libevent,其使用标准C语言编写,支持Windows、Linux、Mac等等主流操作系统,早期版本不支持Windows的IOCP,最新版本已经添加上了,在网上找了一下资料,发现使用IOCP的libevent示例太少,于是结合网上的资料,自己整理编写了一下libevent使用IOCP的小例子。该示例同时支持IPV4以及IPV6的连接。

  1. #ifdef __cplusplus
  2. extern "C"
  3. {
  4. #endif
  5.  
  6. //包含所需要的头文件
  7. #include "event2/event.h"
  8. #include "event2/listener.h"
  9. #include "event2/bufferevent.h"
  10. #include "event2/thread.h"
  11. #include "event2/buffer.h"
  12.  
  13. #ifdef __cplusplus
  14. };
  15. #endif
  16.  
  17. #ifdef _MSC_VER
  18. #pragma comment(lib,"ws2_32.lib")
  19. #pragma comment(lib,"libevent_core.lib")
  20. #endif
  21.  
  22. //监听回调函数
  23. void listener_cb(evconnlistener *listener, evutil_socket_t fd,
  24. struct sockaddr *sock, int socklen, void *arg);
  25.  
  26. //从Socket接收消息的回调函数
  27. void socket_read_cb(bufferevent *bev, void *arg);
  28.  
  29. //从Socket事件的回调函数
  30. void socket_event_cb(bufferevent *bev, short events, void *arg);
  31.  
  32. int main()
  33. {
  34. WORD wVersionRequested;
  35. WSADATA wsaData;
  36. int err;
  37.  
  38. /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
  39. wVersionRequested = MAKEWORD(2, 2);
  40. //这里必须初始化网络,不然会创建Socket失败
  41. err = WSAStartup(wVersionRequested, &wsaData);
  42. if (err != 0) {
  43. /* Tell the user that we could not find a usable */
  44. /* Winsock DLL. */
  45. printf("WSAStartup failed with error: %d\n", err);
  46. return 1;
  47. }
  48.  
  49. struct sockaddr_in sin;
  50. memset(&sin, 0, sizeof(struct sockaddr_in));
  51. sin.sin_family = AF_INET;
  52. sin.sin_port = htons(2000);
  53.  
  54. struct sockaddr_in6 sin6;
  55. memset(&sin6, 0, sizeof(struct sockaddr_in6));
  56. sin6.sin6_family = AF_INET6;
  57. sin6.sin6_port = htons(2000);
  58.  
  59. //告诉libEvent使用Windows线程
  60. //这句是必须的,不然会导致event_base_dispatch时一直处于Sleep状态,无法正常工作
  61. evthread_use_windows_threads();
  62.  
  63. struct event_config* cfg = event_config_new();
  64. event_config_set_flag(cfg,EVENT_BASE_FLAG_STARTUP_IOCP);
  65. //根据CPU实际数量配置libEvent的CPU数
  66. SYSTEM_INFO si;
  67. GetSystemInfo(&si);
  68. event_config_set_num_cpus_hint(cfg,si.dwNumberOfProcessors);
  69.  
  70. event_base *base;
  71. base = event_base_new_with_config(cfg);
  72. event_config_free(cfg);
  73.  
  74. // 绑定并监听IPV4端口
  75. evconnlistener *listener = evconnlistener_new_bind(base, listener_cb, base,
  76. LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
  77. 10, (struct sockaddr*)&sin,
  78. sizeof(sin));
  79.  
  80. // 绑定并监听IPV6端口
  81. evconnlistener *listener6 = evconnlistener_new_bind(base, listener_cb, base,
  82. LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
  83. 10, (struct sockaddr*)&sin6,
  84. sizeof(sin6));
  85.  
  86. //事件分发处理
  87. event_base_dispatch(base);
  88.  
  89. evconnlistener_free(listener);
  90. evconnlistener_free(listener6);
  91. event_base_free(base);
  92. WSACleanup();
  93.  
  94. return 0;
  95. }
  96.  
  97. //一个新客户端连接上服务器了
  98. //当此函数被调用时,libevent已经帮我们accept了这个客户端。该客户端的
  99. //文件描述符为fd
  100. void listener_cb(evconnlistener *listener, evutil_socket_t fd,
  101. struct sockaddr *sock, int socklen, void *arg)
  102. {
  103. char Buffer[256];
  104. sockaddr_in* addr = (sockaddr_in*)sock;
  105. evutil_inet_ntop(addr->sin_family,&addr->sin_addr,Buffer,sizeof(Buffer));
  106. printf("accept a client %d,IP:%s\n", fd,Buffer);
  107.  
  108. event_base *base = (event_base*)arg;
  109.  
  110. //为这个客户端分配一个bufferevent
  111. bufferevent *bev = bufferevent_socket_new(base, fd,
  112. BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
  113.  
  114. bufferevent_setcb(bev, socket_read_cb, NULL, socket_event_cb, NULL);
  115. bufferevent_enable(bev, EV_READ | EV_PERSIST);
  116. }
  117.  
  118. void socket_read_cb(bufferevent *bev, void *arg)
  119. {
  120. char msg[4096];
  121.  
  122. size_t len;
  123. // 这里一行一行的读取
  124. char* p = evbuffer_readln(bufferevent_get_input(bev),&len,EVBUFFER_EOL_ANY);
  125. if(p)
  126. {
  127. // 如果输入exit或者quit则退出程序
  128. // 可以使用event_base_loopexit或者event_base_loopbreak
  129. // 它们的区别是前者会把事件处理完才退出,后者是立即退出
  130. if(!strcmp(p,"exit"))
  131. event_base_loopexit(bufferevent_get_base(bev),NULL);
  132. else if (!strcmp(p,"quit"))
  133. event_base_loopbreak(bufferevent_get_base(bev));
  134.  
  135. printf("recv data:%s\n", p);
  136.  
  137. int n = sprintf_s(msg,"srv recv data:%s\n",p);
  138. //发送消息给客户端
  139. bufferevent_write(bev, msg, n );
  140.  
  141. // 这里记得把分配的内存释放掉,不然会内存泄漏
  142. free(p);
  143. }
  144. }
  145.  
  146. void socket_event_cb(bufferevent *bev, short events, void *arg)
  147. {
  148. if (events & BEV_EVENT_EOF)
  149. printf("connection closed\n");
  150. else if (events & BEV_EVENT_ERROR)
  151. printf("some other error\n");
  152.  
  153. //这将自动close套接字和free读写缓冲区
  154. bufferevent_free(bev);
  155. }
  1.  

libevent使用IOCP网络模型的示例的更多相关文章

  1. 几个网络模型的示例代码(BlockingModel、OverlappedModel、WSAEventSelect、CompletionRoutine)..c++

    作者的blog:猪)的网络编程世界 几个网络模型的示例代码代码包括了下面几个模型的示例:BlockingModel(阻塞模式).OverlappedModel(基于事件的重叠I/O).WSAEvent ...

  2. Libevent源码分析 (1) hello-world

    Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libeven ...

  3. 简单对比 Libevent、libev、libuv

    Libevent.libev.libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library). 异步事件库本质上是提供异步事件通知(Asynchronous Ev ...

  4. windows 平台使用 VS2017 编译 libevent 源码

    一 依赖库编译 先要将其依赖的库编译好,其中openssl需要编译到libevent中,编译成libevent_openssl.lib库,zlib在新版本中只有示例用到. 1)windows 平台使用 ...

  5. 网络库libevent、libev、libuv对比

    Libevent.libev.libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library). 异步事件库本质上是提供异步事件通知(Asynchronous Ev ...

  6. libevent编程疑难解答

    http://blog.csdn.net/luotuo44/article/details/39547391 转载请注明出处:http://blog.csdn.net/luotuo44/article ...

  7. EQueue - 一个纯C#写的分布式消息队列介绍2

    一年前,当我第一次开发完EQueue后,写过一篇文章介绍了其整体架构,做这个框架的背景,以及架构中的所有基本概念.通过那篇文章,大家可以对EQueue有一个基本的了解.经过了1年多的完善,EQueue ...

  8. 发布一个UDP调试助手

    UDP协议适用于那种频繁通信,但是可以容忍一些丢包的应用,比如GPS的定位应用. 调试UDP助手,可以定时发送,输出文本, 记录收到时间. 1. 该工具基于IOCP网络模型,调试UDP服务使用的一个工 ...

  9. windows下的IO模型之事件选择(WSAEventSelect)模型

    异步选择模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知.对于异步选择模型采用的网络事件来说,它们均可原封不动地移植到事件选择模型.事件选择模型和异步选择模型最主要的 ...

随机推荐

  1. CSS和jQuery分别实现图片无缝滚动效果

    一.效果图 二.使用CSS实现 <!DOCTYPE html> <html> <head> <meta charset="utf-8"&g ...

  2. 前端用vue,后端需要nodejs吗?

    其实用脚趾头想想也知道:后端用不用node,和前端用不用vue,二者完全没关系. 那为何用vue和vue插件开发前端的时候,经常需要各种npm install呢?为何要在本地安装node环境? 本地需 ...

  3. pickle模块 和json模块

    pickle和json序列号 json模块是所有语言通用的,可以用来把一些数据转成字符串存储在文件中 import json l=[,,] with open('t3',mode='w',encodi ...

  4. printf sscanf进阶

    printf ; printf (3d", a);//将打印 035 printf(“%-*s”, width, string): “*”: 在这里用width代替,其实和printf(“% ...

  5. 7、执行 suite 后,result.html 测试报告中,测试结果全部显示为通过原因分析

    测试用例中,断言 异常后,必须 raise 抛出异常, 若无raise ,则测试报告中测试结果全部显示为通过. 抛出后,显示实际测试结果,通过/未通过 __author__ = 'Administra ...

  6. Dubbo---注册中心

    1.Multicast 注册中心 1.1 Multicast 注册中心   不需要启动  任何中心节点,只要广播地址一样,就可以互相发现. 1.2 1.3 配置   2.zookeeper 注册中心( ...

  7. mac上安装mamp集成环境

    深知mac配置环境是个坑,本人之前用的是xampp因为近期需要mongodb扩展,死活装不明白,索性就换了一个集成环境,在网上找了好多,最后选择了mamp 因为正版的要收费,所以在下载了N个以后终于找 ...

  8. 每天一个Linux命令:ls(1)

    ls ls命令用于显示指定工作目录下之内容(列出目前工作目录所含之文件及子目录). 格式 ls [-alrtAFR] [name...] 参数选项 参数 备注 -a 列出目录下的所有文件,包括以 . ...

  9. centos7安装kylo0.10.1

    安装环境centos7,kylo版本0.10.1 常用的链接地址 kylo官网:https://kylo.io/ kylo文档:https://kylo.readthedocs.io/ 下载地址 官网 ...

  10. mybatis的核心对象图解