在网络编程中,正常的TCP断开是这样的:
但是,四次挥手时当客户端调用close(socket套接字)主动断开以后,只是使用socket函数很难去判断客户端什么时候结束,应该什么时候在服务器去调用close。
这里有一下几种方法:
1.在muduo中,是客户端使用shutdown(sockfd, SHUT_WR)函数关闭写端连接,这样在服务端的epoll监听队列中,该文件描述符会产生EPOLLUP事件,在服务端就关闭连接,通过epoll事件的方式来告诉服务端关闭文件描述符。同时使用Socket::setKeepAlive(类似心跳包)防止客户端崩溃或者网络错误,没有能发送fin信号。
2.还有可以自定义结束协议,比如如果发送的数据中有一些特定的字符,那么服务端读到就自动关闭连接
3.还可以使用close并设置SO_LINGER选项
4.使用心跳包
在四次握手的过程中,发生这些问题,系统会如何处理:
1.如果只是客户端调用close,而服务器没有调用close,服务器这个端口就会一直处于close_wait状态,并且不会自动消除,而客户端会处于fin-wait-2状态,注意:close_wait状态不会超时消除,会一直占用资源,积累越多就会内核崩溃,fin-wait-2状态则在一些操作系统下可以自动超时关闭,这样就可以自动释放了,windows和linux都可以设置。可以查看这篇博客https://www.cnblogs.com/zhangshiwen/p/8312869.html
2.如果客户端主动close,但是服务端崩溃了,连ack也没有发出来,那么客户端就是fin-wait-1状态,这个状态会超时自动关闭的,具体可以看这篇微博。https://blog.csdn.net/dog250/article/details/81697403?utm_source=copy
3.服务器:发出FIN,客户端回复ACK,进入TIME_WAIT状态
客户端:没有close(),处于close_wait()状态,
接着向服务器继续发送数据,会出现什么情况?
客户端:因为对方关闭(相当于管道中对方的读端关闭写端写满缓冲区就会触发SIGPIPE信号,操作系统会强制关闭写端),客户端继续写的话,会触发SIGPIPE信号,操作系统会强制关闭客户端
shutdown和close函数的区别,可以参考这篇博客:https://blog.csdn.net/lgp88/article/details/7176509