zoukankan      html  css  js  c++  java
  • 跨平台网络库(采用C++ 11)

    I:跨平台设计基础

      在windows下使用0字节的WSARecv/WSASend(读写)作为读写检测,将IOCP作为一个通知模型,而"抛弃"它的异步模型。

     即:把它当作epoll来用。使得(方便)网络库的设计(譬如socket的读写处理)在windows和linux下实现统一:  底层获得读写通知,应用层(网络库中)自己处理读写。

    II:单线程EventLoop  

      1:EventLoop是一个单线程的网络IO循环,使用一个iocp(epoll)实例,管理多个DataSocket。  

         通过EventLoop的addConnection接口为它添加DataSocket(并传入一个回调),并会在EventLoop接手它后触发传入的回调函数--处理链接建立之后的业务逻辑。  

         DataSocket 即为一个客户端连接-会话,用户可以为它设置事件回调函数。  

           setDataHandle:设置收到消息后的回调函数。  

           setDisConnectHandle:设置链接断开后的回调函数。

         当然我们也可以通过disConnect主动断开会话的网络连接。 

      2:EventLoop实现线程安全的wakeup和异步消息队列,用于外部逻辑线程投递异步操作(以及唤醒,以让eventloop尽可能更快的处理请求)。

      3:std::shared_ptr作为packet类型,用于将同一个packet投递给多个客户端DataSocket(避免分配多个消息),DataSocket 内置一个队列,保存当前pending在它上的待发packet list。  

         之所以采用std::shared_ptr,是因为它自带引用计数处理,可以方便的应对同一个消息包发送给多个客户端时,消息包的分配和释放问题(即此消息全部发送给它的目的客户端,那么此消息就可以回收),

        无需自己再写一套消息包设计了。

      注:目前linux下给客户端flush发送网络消息时,采用writev提高效率,但windows上没有找到相关函数(WSASend不满足要求),但可以在某些时候将消息memcpy到一个缓冲区,然后一次性send(以减少send系统调用次数))。

    III: 封装EventLoop的TCPServer  

      1:TCPServer处理Listen逻辑以及为新到的链接分配(通过EventLoop的addConnection接口)一个EventLoop。

      2!:可从源码中看到DataSocket的事件回调函数所附带的参数是DataSocket*, 但是 TcpServer回调函数参数中,表示会话标识的类型为:int64 id,而非裸指针。  

           这是因为TCPServer多被用于多线程设计,此时会话的有效性(避免串话)(以及内存的有效性-野指针问题)需要保证,而裸指针并非安全的。

      3:第二点说到TcpServer多用于多线程设计时,具体如下:

        在它的回调函数中,我们可以将消息投递到一个逻辑线程的消息队列,并wakeup逻辑线程的EventLoop),当逻辑线程被唤醒后,从消息队列中同步读取消息,然后处理。  

       而当逻辑线程需要发送消息则使用: TCPServer的send接口,参数是一个int64_t id 表示要发送消息的会话,紧接着是一个Packet,表示消息内容。  

      当然!:TCPServer的回调函数中可以立即处理,而非投递到别的线程进行协作,这样用起来当然更简单了。

      譬如在某些网络服务中,不需要很耗时的处理,而仅仅是IO密集型(比如网关),  那么建议直接在回调函数中进行处理(譬如转发)。

    注: 此网络库参考了 muduo:https://github.com/chenshuo/muduo

    另外致谢:sniperhw:http://www.cnblogs.com/sniperhw 近几年的指点

    网络库代码地址: https://github.com/IronsDu/accumulation-dev/tree/master/cpp_net

     目前main.cpp实现的是一个ping pong测试(一个进程内:服务器用TCPServer,用多个客户端线程跑各自的EventLoop)。

      从main.cpp也可以看到 单线程EventLoop和TCPServer多线程加消息队列的使用方式。

    (VS版本至少 VS2013),Linux下签出整个项目后进入/examples/DNet/DNet目录, (我用的g++ 4.9版本 )再使用命令:

    g++ -I./../../../cpp_common -I./../../../common eventloop.cpp datasocket.cpp TCPServer.cpp main.cpp -std=c++0x -lrt

    TODO::代码中有一些TODO,表示晦涩或者我不太确定没问题~HOHO

    另外我很期待后面要做的广播测试(类似MMO的AOI,多个玩家同时移动,要广播给周围N个玩家)。

    目前ping pong测试(客户端和服务器在同一个进程内,编译时不开任何优化)在我的机器(AMD Athlon(tm) 7750 Dual-Core Processor,1.3G Hz, CentOS 6.3):

    1:TCPServer使用一个线程,并将收到的消息投递到逻辑线程进行ping pong处理。

    100个链接,消息包大小为4K,每秒吞吐为190M/s。

    1000个链接,消息包大小为4K,每秒吞吐为135M/s。

    10000个链接,消息包大小为4K,每秒吞吐为125M/s。

    2:TCPServer使用一个线程,直接在自身的消息回调函数中进行ping pong处理。

    100个链接,消息包大小为4K,每秒吞吐为315M/s。

    1000个链接,消息包大小为4K,每秒吞吐为190M/s。

    10000个链接,消息包大小为4K,每秒吞吐为160M/s。

  • 相关阅读:
    xcode 4.2 运行 4.3 simulator出错, dyld: Library not loaded: /usr/lib/libc++abi.dylib
    Mathematica 进阶 自定义抽象矩阵运算
    php正则表达式函数 preg_replace用法
    jQuery DIV圆角插件之jquery.corner.js jQuery插件怎么用?
    JQuery获取和设置Select选项方法
    javascript+css无刷新实现页面样式的更换
    Nginx 高性能的 HTTP 和 反向代理 服务器
    240多个jquery插件
    imgPreview在线预览
    Linux下查看apache连接数
  • 原文地址:https://www.cnblogs.com/irons/p/4179560.html
Copyright © 2011-2022 走看看