【Muduo源码剖析笔记】 网络库之TcpConnection
TcpConnection
我们会在基类中继承 std::enable_shared_from_this 来使得在该类的方法中能够使用 shared_ptr 托管的 this 指针。由TCPconnection管理管道和socket。
enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting };
EventLoop* loop_; //指向这个TCP连接所属的loop
const string name_; //连接名字?
StateE state_; // FIXME: use atomic variable
bool reading_;
// we don't expose those classes to client.
std::unique_ptr<Socket> socket_; //是一个指针,指向socket
std::unique_ptr<Channel> channel_; //指向一个channel 自己没有
const InetAddress localAddr_; //本地地址
const InetAddress peerAddr_; //远程地址
ConnectionCallback connectionCallback_; //连接回调函数对象
MessageCallback messageCallback_;
WriteCompleteCallback writeCompleteCallback_;
HighWaterMarkCallback highWaterMarkCallback_;
CloseCallback closeCallback_;
size_t highWaterMark_;
Buffer inputBuffer_; //拥有缓冲区,是net中定义的buffer。
Buffer outputBuffer_; // FIXME: use list<Buffer> as output buffer.
boost::any context_;
初始化函数
TcpConnection::TcpConnection(EventLoop* loop,
const string& nameArg,
int sockfd,
const InetAddress& localAddr,
const InetAddress& peerAddr)
: loop_(CHECK_NOTNULL(loop)),
name_(nameArg),
state_(kConnecting),
reading_(true),
socket_(new Socket(sockfd)),
channel_(new Channel(loop, sockfd)),
localAddr_(localAddr),
peerAddr_(peerAddr),
highWaterMark_(64*1024*1024)
首先会把指定这个这个Connection归属于哪个loop,设置reading标志位为true。以这个sockfd为初始化函数分配一个新的socket对象。然后用这个loop和sockfd初始化这个channel。(也就是管道需要知道自己在哪个loop里面和管理了哪个sockfd)。后续函数体中就为管道设置了 读回调函数、写回调函数、关闭回调函数和错误回调函数。
读回调函数:handleRead
写回调函数:handleWrite
关闭回调函数:handleClose
错误回调函数:handleError
void TcpConnection::handleWrite()
属于子线程运行的函数。是发生写事件的时候会调用的回调函数。把buffer中的readble区域发送到socket中。首先判断如果是写通道(enable_writing被调用)。就会往channel里面写buffer的内容。如果写进去了,那么就把outputbuffer retrieve n个字节。(n是实际写的字节数)。如果Buffer没有可读的空间了,就把channel的可读事件关闭。比如有这个管道全部数据写完就要执行的函数,就会执行。
void TcpConnection::handleRead(Timestamp receiveTime)
这个socket发生可读事件的话,就会把数据读到inputBuffer中。再调用messageCallback_(shared_from_this(), &inputBuffer_, receiveTime)
TcpConnection::~TcpConnection()
析构函数输出LOG信息。
void TcpConnection::send(const StringPiece& message)
首先确认运行send函数的线程和创建这个loop的线程是同一个,然后就直接调用sendInLoop(message)。
如果不是本线程调用send,会调用loop的runInloop。runInloop唤醒子线程,然后把sendInLoop让子线程调用。
void TcpConnection::sendInLoop(const void* data, size_t len)
像是要把buf的数据送给TCP Connection调用的数据。