本节研究服务器TcpServer的实现;
整体类图
服务器TcpServer
(1)TcpServer由用户直接使用,生命周期由用户控制,用户设置好相应的回调MessageCallback、ConnectionCallback传递给TcpServer即可;MessageCallback为连接上有接收数据时调用的回调(处理业务逻辑),这些数据存放在连接的应用层接收缓冲区中;ConnectionCallback在连接建立和断开时,都会直接的回调,主要是通知用户进行相应的处理;
(2)在TcpServer中,建立连接描述符和TcpConnection之间的关系,通过stl中map来实现,map<int, TcpConnectionPtr>这样可以高效的查找,删除,插入操作;
(3)TcpServer本身有一个EventLoop,主要用于对接受连接事件的监听,;EventLoopPool也为TcpServer的成员,使用轮转法为每一个新的TcpConnection选择EventLoop;
示意图如下:
TcpServer接受连接示意图如下
接收数据回调示意图如下
TcpServer断开连接示意图如下
TcpServer
TcpServer声明
class TcpConnection; class EventLoop; class Acceptor; class EventLoopPool; class TcpServer final { public: TcpServer(const TcpServer&) = delete; TcpServer& operator=(const TcpServer&) = delete; explicit TcpServer(EventLoop* loop, const InetAddress& serverAddr, size_t loopNums); void start(); typedef std::shared_ptr<TcpConnection> TcpConnectionPtr; void setMessageCallback(const MessageCallback& cb) { _messageCallback = cb; } void setConnectionCallback(const ConnectionCallback& cb) { _connectionCallback = cb; } private: void _newConnection(int connfd, const InetAddress& peerAddr); void _removeConnection(const TcpConnectionPtr& conn); void _removeConnectionInLoop(const TcpConnectionPtr& conn); InetAddress _serverAddr; size_t _loopNums; EventLoop* _loop; std::unique_ptr<Acceptor> _acceptor; std::unique_ptr<EventLoopPool> _loopPool; std::map<int, TcpConnectionPtr> _connectionMaps; MessageCallback _messageCallback; ConnectionCallback _connectionCallback; };
说明几点:
(1)MessageCallback为连接上有接收数据时调用的回调(处理业务逻辑),这些数据存放在连接的应用层接收缓冲区中;ConnectionCallback在连接建立和断开时,都会直接的回调,主要是通知用户进行相应的处理;
(2)在TcpServer中,建立连接描述符和TcpConnection之间的关系,通过stl中map来实现,map<int, TcpConnectionPtr>这样可以高效的查找,删除,插入操作;
(3)TcpServer本身有一个EventLoop,由用户来传入,主要用于对接受连接的事件的监听;EventLoopPool也为TcpServer的成员,使用轮转法为每一个新的TcpConnection选择EventLoop;_loopNums为EventLoopPool的EventLoop数量;
(4)std::unique_ptr<Acceptor> _acceptor是TcpServer的成员,用于接受新连接,_newConnection为注册给_acceptor的回调,当有新连接时,会回调该函数;
(5)_serverAddr为服务器的监听地址;
构造函数
TcpServer::TcpServer(EventLoop* loop, const InetAddress& serverAddr, size_t loopNums) : _serverAddr(serverAddr), _loopNums(loopNums), _loop(loop), _acceptor(new Acceptor(_serverAddr, _loop)), _loopPool(_loopNums > 0 ? (new EventLoopPool(_loopNums)) : nullptr) { _acceptor->setNewConnectionCallback(std::bind(&TcpServer::_newConnection, this, std::placeholders::_1, std::placeholders::_2)); }
说明几点:
(1)当_loopNums不大于0时,就使用master线程中EventLoop进行对TcpConnection的管理,意味着这是一个单线程单EventLoop的服务器;
启动EventLoopPool中各个IO线程
void TcpServer::start() { _loopPool->start(); }
接受新连接
void TcpServer::_newConnection(int connfd, const InetAddress& peerAddr) { EventLoop* loop; if ( _loopPool) { loop = _loopPool->getNextLoop(); } else { loop = _loop; } LOG_INFO << "TcpServer::_newConnection [" << connfd << "] from " << peerAddr.hostNameString(); TcpConnectionPtr conn(new TcpConnection(connfd, loop, peerAddr, _serverAddr)); assert(_connectionMaps.find(connfd) == _connectionMaps.end()); _connectionMaps[connfd] = conn; conn->setMessageCallback(_messageCallback); conn->setConnectionCallback(_connectionCallback); conn->setCloseConnectionCallback(std::bind(&TcpServer::_removeConnection, this, std::placeholders::_1)); conn->connectEstablished(); }
说明几点:
(1)该函数只要由Acceptor中accept后新连接的回调函数;
(2)创建TcpConnection后,放入_connectionMaps中,这样TcpServer也就持有了TcpConnection,如果TcpServer不删除TcpConnection,那么TcpConnection是不会析构的;
(3)setMessageCallback,setConnectionCallback,setCloseConnectionCallback分别为设置信息接收时的用户回调,连接建立和断开时的用户回调,TcpServer连接断开回调;connectEstablished为让IO线程开始接管TcpConnection上的事件监听;
移除连接
void TcpServer::_removeConnection(const TcpConnectionPtr& conn) //thread safe { _loop->queueInLoop(std::bind(&TcpServer::_removeConnectionInLoop, this, conn)); } void TcpServer::_removeConnectionInLoop(const TcpConnectionPtr& conn) { LOG_DEBUG << "use_count: " << conn.use_count(); _connectionMaps.erase(conn->connfd()); LOG_DEBUG << "TcpServer::_removeConnection fd[" << conn->connfd() << "] " << conn.use_count(); }
说明几点:
(1)_removeConnection为上述TcpConnection通过setCloseConnectionCallback设置的TcpServer连接断开回调,最后连接断开时,为保证线程安全性,将会在TcpServer本身的EventLoop中进行真正的删除;