活着就是,
一个个无可替代的日子里的累积。
--- 坂本健一 ---
1 TCP通信状态
在四次挥手问题中,客户端向服务端发送FIN请求断开连接,服务端返回应答,并也发送一个FIN请求进行断开连接,客户端收到后就返回应答。这里服务端发送ACK和FIN可以合并为一次,所以也能成为三次挥手!所以建立连接和断开连接本质上是没有区别的,那为什么还要强调四次挥手呢?因为一方端口连接,另一方可能还有需要发送的数据,所以有可能是进行四次挥手。
在这里出现了这样几个状态:TIME_WAIT , CLOSE_WAIT,FIN_WAIT。
- TIME_WAIT(时间等待)状态: TIME_WAIT是主动关闭方在完成最后一次ACK发送后的状态。这个状态存在的目的是为了确保连接被动关闭方能够收到最后一个ACK确认包,同时防止在网络中延迟的数据包影响新连接的建立。
- CLOSE_WAIT(关闭等待)状态: CLOSE_WAIT是连接被动关闭方在收到对方发送的FIN请求后,发送ACK确认进入的状态。在这个状态下,应用程序可能还有未处理的数据需要发送,因此需要等待应用程序处理完这些数据后,才能发送FIN请求来关闭连接。如果应用程序没有及时关闭连接,可能会导致大量的CLOSE_WAIT状态,从而消耗系统资源。CLOSE_WAIT状态表示被动关闭方正在等待关闭。
我们来验证两个状态:TIME_WAIT , CLOSE_WAIT。
1.1 验证CLOSE_WAIT状态
我们先来看一看服务端的CLOSE_WAIT状态:在网络套接字代码中,只要服务器不关闭文件描述符其状态就会处于CLOSE_WAIT状态!
在Tcpserver的回调函数中,当服务端套接字接受到了新的的连接就会创建新线程执行Execute
函数。在完成service函数之后,按理来说完成一次通信之后要关闭对应的文件描述符,这里我们不关闭文件描述符:
static void *Execute(void *args)
{
pthread_detach(pthread_self()); // 线程分离!!!
// 执行Service函数
TcpServer::ThreadData *td = static_cast<TcpServer::ThreadData *>(args);
// 直接进行IO
std::string reqstr;
// 这里默认读取到的是完整的请求
ssize_t n = td->_sockfd->Recv(&reqstr);
if