【网络组件】TCP连接

本节主要研究TCP连接TcpConnection的实现;

TcpConnection(1)TcpConnection采用C++中shared_ptr来管理;TcpConnection可被用户持有,当TcpConnection析构时,才会close其连接描述符;也就是说即使TCP连接即使已经关闭了,但是用户仍旧持有TcpConnection,TcpConnection的连接描述符仍然不会被关闭;这主要是为了防止串话,假设先前用户仍旧持有TcpConnection,但是连接描述符被其它的TcpConnection使用,那就会造成先前用户持有TcpConnection的串话,它持有的连接描述符又有了新的TCP连接,TcpConnection的连接描述符关闭时,新的TCP连接也将会被关闭;因此程序应该保证TCP连接关闭以后,TcpConnection也应该析构;(2)本节仅仅独立的解释TcpConnection,TcpConnection与Acceptor、TcpServer和Connecor、TcpAcceptor之间的交互,将会由以后的博客介绍;

状态转换图

(1)初始状态为Connecting;

(2)当TCP连接建立以后,状态从Connecting变成Connected;

(3)当有写关闭以后以后,状态由Connected变成Disconnecting,我们并不能立即执行写关闭;应该设置状态在处于Disconnecting时,将当前的应用层发送缓存数据发送完以后再继续shutdown;

(4)当执行_headClose时,将会到达最后的状态Disconnected;

状态转换图如下:

TcpConnectionTcpConnection声明

namespace Net{class EventLoop;class Event;class TcpConnection final : public std::enable_shared_from_this<TcpConnection>{public: TcpConnection(const TcpConnection&) = delete; TcpConnection& operator=(const TcpConnection&) = delete; TcpConnection(int connfd, EventLoop* loop, const InetAddress& peerAddr, const InetAddress& localAddr); ~TcpConnection(); enum State { Connecting, Connected, Disconnecting, Disconnected}; void setState(State state) {_state = state; } //连接接收到信息时,执行的用户函数的回调 void setMessageCallback(const MessageCallback& cb) {_messageCallback = cb; } //连接建立或断开时,执行的用户函数的回调 void setConnectionCallback(const ConnectionCallback& cb) {_connectionCallback = cb; } //连接断开时,,执行的TcpSever的removeConnection函数 typedef std::function<void(TcpConnectionPtr)> CloseConnectionCallback; void setCloseConnectionCallback(const CloseConnectionCallback& cb) {_closeConnectionCallback = cb; } void connectEstablished(); void send(const void* buf, size_t len); void send(const std::string& message); void shutdown(); bool connected() const {return _state == Connected; } int connfd() const {return _connfd; } EventLoop* loop() const {return _loop; } Buffer& inputBuffer() {return _inputBuffer; }private: void _sendInLoop(const void* buf, size_t len); void _sendInLoopByMessage(const std::string& message); void _shutdownInLoop(); void _connectEstablishedInLoop(); void _handleRead(); void _handleWrite(); void _handleClose(); void _handleError(); int _connfd; EventLoop* _loop; std::unique_ptr<Event> _connEvent; InetAddress _peerAddr; InetAddress _localAddr; State _state; Buffer _inputBuffer; //read from connfd Buffer _outputBuffer; //write to connfd MessageCallback _messageCallback; ConnectionCallback _connectionCallback; CloseConnectionCallback _closeConnectionCallback;};typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;}说明几点:

(1)_inputBuffer,_outputBuffer分别是该Tcp连接的应用层接收缓冲和发送缓冲;_peerAddr,_localAddr分别为TCP连接的远程地址对和本地地址对;

(2)_handleRead();handleWrite();_handleClose();_handleError();分别是监听到相对应的事件类型后,执行的回调函数;

(3)State _state;表示TCP的连接状态,状态分别有enum State { Connecting, Connected, Disconnecting, Disconnected};对应上述的状态转换图;

(4)Tcp连接还通过发送数据send函数,以及写关闭函数shutdown;当调用写系列的函数并不是本身TCP连接的IO线程时,会将对应的回调放入的IO线程中执行,因此分别有_sendInLoop(const void* buf, size_t len); _sendInLoopByMessage(const std::string& message);_shutdownInLoop();系列函数;

(5)connectEstablished()为TCP连接建立的外部调用函数,同样有对应的IO线程回调函数_connectEstablishedInLoop();

(6) MessageCallback _messageCallback为TCP连接接收到数据后执行的用户回调函数,此时用户可能有足够的数据宝可以处理;ConnectionCallback _connectionCallback;为TCP连接建立和断开时都需要执行的回调函数,来让用户处理对持有TCP连接的逻辑;

(7)CloseConnectionCallback _closeConnectionCallback为TCP连接断开时,TcpServer需要执行的回调函数,为保证线程安全,需要在TcpServer本身的线程中进行处理;

TcpConnection构造和析构

TcpConnection::TcpConnection(int fd, EventLoop* loop_, const InetAddress& peerAddr, const InetAddress& localAddr):_connfd(fd),_loop(loop_),_connEvent(new Event(_connfd, _loop)),_peerAddr(peerAddr),_localAddr(localAddr),_state(Connecting){ assert(_state == Connecting); _connEvent->setReadCallback(std::bind(&TcpConnection::_handleRead, this)); _connEvent->setWriteCallback(std::bind(&TcpConnection::_handleWrite, this)); _connEvent->setErrorCallback(std::bind(&TcpConnection::_handleError, this)); _connEvent->setCloseCallback(std::bind(&TcpConnection::_handleClose, this));}//if we do not do this, when client close fd, it recives ACK, enters FIN_WAIT_2, and the server is in CLOSE_WAIT;TcpConnection::~TcpConnection(){ if (_connfd >= 0)::close(_connfd); LOG_TRACE << "TcpConnection::~TcpConnection()";}

说明几点:

(1)TcpConnection的构造是在其他线程中调用,为了保证线程安全性,TcpConnection本身被管理的IO线程此时还并没有真正接管此TcpConnection,要一直等到connectEstablished时;

(2)TcpConnection的析构函数中,我们需要close到连接本身,发送方和接收方可能处于通信死锁的状态;

IO线程接管TCP连接原以为“得不到”和“已失去”是最珍贵的,可原来把握眼前才是最重要的。

【网络组件】TCP连接

相关文章:

你感兴趣的文章:

标签云: