快速构建MMO服务器框架(七)高并发TCP网络框架

忙活了一个多星期,差不多把基于TCP的高并发连接网络架构测试稳定了。

目的:利用多线程把网络连接及数据包压缩/解压、加密/解密等等耗时的操作分流(asio对这些没有原生的支持),顺带提供线程池框架。只对游戏逻辑层暴露出单线程的外观,隔离底层多线程的复杂度。

结构如下图(未遵循什么标准,将就着看吧):

快速构建MMO服务器框架(七)高并发TCP网络框架_第1张图片

 

TCPSessionHandler:暴露给逻辑层的类,内部负责通过TCPIOThreadManager跟挂载于某个线程的TCPSession进行交互,对上层屏蔽多线程细节。声明如下:class TCPSessionHandler : public std::enable_shared_from_this<TCPSessionHandler>, public boost::noncopyable { public: // ==================== TYPEDEFS ======================================= // ==================== LIFECYCLE ======================================= TCPSessionHandler(); virtual ~TCPSessionHandler() {} // ==================== OPERATIONS ======================================= // sends message to remote endpoint, the content of message would be consumed void SendMessage(NetMessage& message); // sends message to remote endpoint, the content of message would be consumed void SendMessage(NetMessage&& message); // closes the session void Close(); // true if the session is closed. bool IsClosed() { return kInvalidTCPSessionID == session_id_; } // called when connection complete. virtual void OnConnect() = 0; // called when NetMessage received. virtual void OnMessage(const NetMessage& message) = 0; // called when TCPSession closed. virtual void OnClose() = 0; };  

(注:本文代码风格尽量遵循 google c++ style guide )

NetMessageList:NetMessage定义为逻辑上有明确分界的网络消息,一个或多个NetMessage组成NetMessageList。

TCPIOThreadManager:管理一个或多个TCPIOThread,其中一个TCPIOThtread作为主线程逻辑运行。

CommandList:线程间交互的命令队列,也是整个框架中唯一的线程间同步方式,稍候详述。

TCPIOThread:IO线程,通过CommandList也可作为工作线程使用,每个线程使用asio的io_service处理多个TCPSession。

NetMessageFilterInterface:网络消息过滤器接口(上图省略了Interface因为太长了),可以自定制,通常封装组包、压缩、加密等流程,以适应不同的逻辑层协议需求。

TCPSession:后台网络连接,不区分服务端/客户端,负责处理网络数据的发送和接收。


外层还有两个类:TCPServer和TCPClient,可以关联到同一个TCPIOThreadManager,以适应多服架构中某台服务器既是TCP服务器又是其它服务器的客户端的需求。

示例代码:

int main(int argc, char** argv) { TCPIOThreadManager manager(1, // thread num boost::posix_time::millisec(2)); // sync interval unsigned short int port = 20000; TCPServer server({boost::asio::ip::tcp::v4(), port}, manager, &MyHandler::Create, &MyFilter::Create); manager.Run(); return 0; } 

客户端也类似。

 

线程同步策略:

上述线程间同步采用了Command模式,借助了c++ 0x的function。CommandList的定义:


typedef std::list<std::function<void ()>> CommandList;  

每个线程每隔一段时间就把要发往其它线程的Command批量发送,因为list的splice只是几个指针的操作,这个过程可以通过自旋锁高效的完成(psydo code):

CommandList thread1.commands_to_be_sent_; CommandList thread2.commands_received_; //thread1: { thread1.commands_to_be_sent_.push_back(command); ...; thread2.spinlock_.lock(); thread2.commands_received_.splice(thread2.commands_received_.end(), thread1.commands_to_be_sent_); //把thread1.commands_to_be_sent_连接到thread2.commands_received_的尾部 thread2.spinlock_.unlock(); } //thread2: { CommandList templist; thread2.spinlock_.lock(); templist.swap(thread2.commands_received_); //把commands_received_跟临时队列交换再处理, //减少lock的时间 thread2.spinlock_.unlock(); for (auto it = templist.begin(); it != templist.end(); ++it) (*it)(); templist.clear(); }

 

从TCPSessionHandler到TCPSession的NetMessageList的发送,就是通过这套机制来实现,几乎可以忽略线程锁开销。

剩下的问题:NetMessage内部变长缓冲用了vector来实现,动态内存分配可能会带来效率上的隐患。实际应用如果确证,可以用内存池,但是多线程的高效内存池稍微复杂。相关思路改天再写。

 

你可能感兴趣的:(thread,多线程,框架,网络,tcp,服务器)