1. 说明
- 一个TcpConnection类,代码有点长
- 使用了Channel,EventLoop,Socket,Buffer类
- 继承noncopyable,enable_shared_from_this,把当前对象转换成share指针,在connectEstablished()中有用到
- 在连接到来,创建一个TcpConnection对象,立刻使用shared_ptr来管理,引用计数为1.在Channel中维护一个weak_ptr(tie_),将这个shared_ptr对象赋值给tie_,引用计数仍为1.当连接关闭,在handleEvent,将tie_提升,得到一个shared_ptr对象
- 为什么使用那个weak_ptr呢,因为调用顺序是EventLoop–>Channel–>TcpConnection–>TcpServer,在TcpServer中移除TcpConnection,但此时Channel的handleEvent()还正在调用,直接删除TcpConnection对象会产生core dump错误,所以要让TcpConnection对象生命周期要长于handleEvent()函数
- 这里要解决高低水位的问题
- 非阻塞网络编程中要注意发送数据的速度高于对方接受数据的速度,会造成数据在本地内存中的堆积,这带来设计及安全性方面的难度。Muduo对此解决办法是提供两个回调,有的网络库把它们称为“高水位回调”和“低水位回调”,Muduo使用HighWaterMarkCallback和WriteCompleCallback这两个作为高水位回调函数和低水位回调函数.调整发送频率,关注WriteCompleCallback,所有的数据都发送完,WriteCompleCallback回调,然后继续发送.
- WriteCompleCallback
如果发送缓存区被清空,就调用它。TcpConnection有两处可能触发此回调。
TcpConnection::sendInLoop()。
TcpConnection::handleWrite()。 - HighWaterMarkCallback
如果输出缓冲的长度超过用户指定大小,就会触发回调(只在上升沿触发一次)。在非阻塞的发送数据情况下,假设Server发给Client数据流,为防止Server发过来的数据撑爆Client的输出缓冲区,一种做法是在Client的HighWaterMarkCallback中停止读取Server的数据,而在Client的WriteCompleteCallback中恢复读取Server的数据。
2. 变量
-
EventLoop* loop_;
- 必备事件循环类
-
const string name_;
- 连接名字
-
StateE state_; // FIXME: use atomic variable
- 当前状态,值为最后所说的枚举类型中的几个选项
-
bool reading_;
- 判断通道是否可读
-
std::unique_ptr socket_;
- 客户端的socket_
-
std::unique_ptr channel_;
- 该连接所属的通道
-
const InetAddress localAddr_;
- 本地IP地址
-
const InetAddress peerAddr_;
- 连接过来的IP地址
-
ConnectionCallback connectionCallback_;
-
MessageCallback messageCallback_;
-
WriteCompleteCallback writeCompleteCallback_;
-
HighWaterMarkCallback highWaterMarkCallback_;
-
CloseCallback closeCallback_;
- 上面5个回调函数不再赘述
-
size_t highWaterMark_;
- 高水位标记
-
Buffer inputBuffer_;
- 应用层接受缓冲区
-
Buffer outputBuffer_; // FIXME: use list as output buffer.
- 应用层发送缓冲区
-
boost::any context_;
- 任意类型,一个未知类型的上下文对象
-
枚举类型
- enum StateE
3. 函数
1. 私有
-
void handleRead(Timestamp receiveTime);
- 读回调,
-
void handleWrite();
- 写回调
-
void handleClose();
- 关闭连接的回调,设置状态,关闭通道,调用用户设置的回调
-
void handleError();
- 处理错误回调函数
-
void sendInLoop(const StringPiece& message);
-
void sendInLoop(const void* message, size_t len);
- 就是往这个连接的对面write()写数据,把数据写给已连接套接字
- 如果当前output缓冲区没有数据,就直接write(),写完的话如果有writeCompleteCallback_回调函数,就调用
- remaining变量记录还有多少字节需要写,如果大于0的话,就加到outputBuffer_中,发出POLLOUT
- 这里检测缓冲区数据是否大于highWaterMark_,如果大于并且有回调函数的话,调用这个高水位回调函数
-
void shutdownInLoop();
- 调用socket_->shutdownWrite();如果还有数据没发送完,就不能关闭.isWriting()是看是否有POLLOUT
- 应用程序想关闭连接,但有可能正处于发送数据的过程中,output buffer 中有数据还没发完,不能直接调用close();
-
void forceCloseInLoop();
- 调用handleClose()
-
void setState(StateE s) { state_ = s; }
- 如名
-
const char* stateToString() const;
- 如名
-
void startReadInLoop();
- 使通道可读
-
void stopReadInLoop();
- 关闭通道可读
2. 公有
-
构造
- 变量初始化,设置通道的几个回调函数
-
析构
- 只打印日志
-
EventLoop* getLoop() const
- 返回loop_
-
const string& name() const
- 返回name_
-
const InetAddress& localAddress() const
- 返回localAddr_
-
const InetAddress& peerAddress() const
- 返回peerAddr_
-
bool connected() const
- 判断状态state是否_等于kConnected,即是否处于连接状态
-
bool disconnected() const
- 判断状态state是否_等于kDisconnected,即是否处于未连接状态
-
bool getTcpInfo(struct tcp_info*) const;
- 调用socket_->getTcpInfo(tcpi)获得tcp信息赋值到tcpi中
-
string getTcpInfoString() const;
- 返回tcp信息的string字符串
-
void send(const void* message, int len);
-
void send(const StringPiece& message);
-
void send(Buffer* message); // this one will swap data
- 以上几个send,总之就是调用sendInLoop(),不管同步还是异步
-
void shutdown(); // NOT thread safe, no simultaneous calling
- 把shutdownInLoop()加入到事件循环中
- 设置状态,如果还有数据没写,shutdownInLoop()什么事都没做,以后服务端要根据状态再次调用shutdownInLoop()
-
void forceClose();
- 把forceCloseInLoop()加入循环
-
void forceCloseWithDelay(double seconds);
- 实际是调用foreclose()
-
void setTcpNoDelay(bool on);
- 如名
-
void startRead();
- 把startReadInLoop()加入事件循环
-
void stopRead();
- 把stopReadInLoop()加入事件循环
-
bool isReading() const // NOT thread safe, may race with start/stopReadInLoop
- 返回reading_
-
void setContext(const boost::any& context)
-
const boost::any& getContext() const
-
boost::any* getMutableContext()
- 以上三个是对Context的操作
-
void setConnectionCallback(const ConnectionCallback& cb)
-
void setMessageCallback(const MessageCallback& cb)
-
void setWriteCompleteCallback(const WriteCompleteCallback& cb)
-
void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, size_t highWaterMark)
-
void setCloseCallback(const CloseCallback& cb)
- 以上五个如名,设置回调函数
-
Buffer* inputBuffer()
-
Buffer* outputBuffer()
- 以上两个返回如名Buffer
-
void connectEstablished(); // should be called only once
- 连接建立时调用一次,设置状态state_,在channel_中使用tie()把当前对象赋值为一个weak_ptr,这样是为了让TcpConnection的生存周期比Channel长一点
- 设置通道监听,调用连接回调函数,这个是用户指定的回调函数
-
void connectDestroyed(); // should be called only once
- 销毁连接,设置状态,调用用户的回调函数,移除通道