本文共 2809 字,大约阅读时间需要 9 分钟。
在上一篇对Tcpserver的连接事件处理器Acceptor的解析中知道Acceptor为每个连接创建一个TcpConnection结构,通过将这个结构传递给Eventpool实现eventpool和Acceptor的关联。因此TcpConnection是连接后面eventpool的桥梁。本篇将解析TcpConnection类。
首先看一下TcpConnection的类数据成员:TcpConnection::TcpConnection(EventLoop* loop, const string& nameArg, int sockfd, const InetAddress& localAddr, const InetAddress& peerAddr) : loop_(CHECK_NOTNULL(loop)), name_(nameArg), state_(kConnecting), socket_(new Socket(sockfd)), channel_(new Channel(loop, sockfd)), localAddr_(localAddr), peerAddr_(peerAddr), highWaterMark_(64*1024*1024), reading_(true){ channel_->setReadCallback( boost::bind(&TcpConnection::handleRead, this, _1)); channel_->setWriteCallback( boost::bind(&TcpConnection::handleWrite, this)); channel_->setCloseCallback( boost::bind(&TcpConnection::handleClose, this)); channel_->setErrorCallback( boost::bind(&TcpConnection::handleError, this)); LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this << " fd=" << sockfd; socket_->setKeepAlive(true);}
这里主要是四个事件处理函数的设置。事件处理器的具体实现我们后面再详细描述,这里主要还是了解代码框架。下面我们继续看TcpConnection的数据成员。
TcpConnection核心是处理IO事件。作为一个健壮的服务器,肯定是不能直接将需要发送的所有数据写入TCP的内核缓冲区中(不能保证内核有足够的缓冲区),也不能允许用户程序完全把TCP内核缓冲区中的数据全部读到应用程序自己设置的缓存中(不能保证用户程序设置的缓冲区容量能容纳所有读进来的数据),因此是必须在TCP内核缓冲的上面在封装一层数据缓冲区的,这就是inputBuffer_和outputBuffer_的作用了。后面我们还会详细介绍它的实现。这些功能主要是用于TcpConnection的事件处理函数,所以到时候我们详细分析它的事件处理函数就可以了。 通过上面的分析知道,当TcpServer创建TcpConnection时,TcpConnection已经把它和eventpool的桥梁Channel结构初始化完毕了,剩下的就是怎么把这个Channel加入到Eventloop中。这个任务由Tcpserver的newConnection函数(记住TcpConnection结构也是在这个函数中创建的)中的下面这行代码完成:ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
这行代码的作用我们现在可以简单理解为执行TcpConnection中的connectEstablished函数。我们看一下connectEstablished的实现:
void TcpConnection::connectEstablished(){ loop_->assertInLoopThread(); assert(state_ == kConnecting); setState(kConnected); channel_->tie(shared_from_this()); channel_->enableReading(); // enable_reading之后在表示把这个事件添加到了event_loop中了 connectionCallback_(shared_from_this());}
好了,我们看到了熟悉的channel_->enableReading(),记住这行代码表示将该Channel加入到了Eventloop中。可能会问为什么这里没有看到Eventloop结构呢,其实这个Eventloop结构已经存在了channel_中(在Channel的构造函数中可以看到),它是Channel中的一个数据成员。到此为止,我们将TcpConnection通过channel和eventpool连接起来了(回顾一下Acceptor,这个过程很相似)。至于Channel是如何和eventloop连接的,下一篇我们会看Channel的实现,就会知晓答案。