TcpConnection的断开
TcpConnection的断开涉及生存期的管理。如果有兴趣,强烈建议去看看的陈硕的《linux网络编程》
Tcp连接的断开主要分为俩类。
- 主动断开,即服务器主动关闭Tcp连接
- 被动断开,即客户端自己断开
1. 被动断开
被动断开时,TcpConnection会就绪,和消息到来时的状态是一样的。只不过这里readFd返回的是0。
当客户端有消息发送过来时,此时我们收到read的返回值后。假设对端断开,我们收到n=0。此时我们不能直接将handler或者TcpConnection删除。
因为我们此时仍然处于handler和TcpConnection对象的调用栈中。还要执行接下来的事情。如果将对象删除,那么就这段内存将不再安全,发生什么事情,我们将无法预知。
为了安全地删除TcpConnection。我们需要在更外面的栈,即在user此时所处的位置——TcpServer这个类所在区域。我们希望在这里去做。有了之前的那么多使用经验,我们很容易就知道通过回调函数的方式设置到TcpConnection中去,然后让其去调用这个回调函数。
等等,这里好像不对哦,我们依然还在TcpConnection的函数栈中。这里就要我们重新思考Reactor的工作原理。
loop()
{
while(1)
{
auto activeEventPtrList = poller->poll();
for(eachEvent : activeEventPtrList)
{
eachEvent->handleEvent();
}
}
handleTask();
}
可以看到,我们需要退出handleEvent这里的函数栈。需要在handleTask中来删除TcpConnection。
因此我们在removeTcpConnection中在TcpConnection所对应的subReactor->addTask。将删除任务放到这里。
2. 主动断开
思考主动断开的时机。muduo中的断开采用的是延迟断开。什么意思呢?
即当前时刻我要断开TcpConnection,但是前面的时候,可能我有数据已经发送到应用层写缓冲区了。此时的断开仅仅是在做一个标志位状态的改变connected = disconnected。如果有其他数据想要在这之后发送给TcpConnection,我们会禁止这种行为。即我们的应用层写缓冲区不再会有数据添加进去。当应用层写缓冲区数据全部发送完毕时。就真正断开连接。
为什么要半断开?
这个在muduo手册中有详细的介绍。本文上半部分也相当于对手册上练习的图解。