socket shutdown和close的区别
http://www.jianshu.com/p/eecab8d50697
shutdown() doesn't actually close the file descriptor—it just changes its usability. To free a socket descriptor, you need to use close().
-
shutdown是一种优雅地单方向或者双方向关闭socket的方法。 而close则立即双方向强制关闭socket并释放相关资源。
-
如果有多个进程共享一个socket,shutdown影响所有进程,而close只影响本进程。
以下均基于单进程socket。
服务端调用shutdown()
-
server调用shutdown(),此时任何后续的send,recv都是无效的(根据关闭发送还是关闭接收有所不同)。shutdown本身并不影响底层,也就是说,此前发出的异步send/recv不会返回。其次,在所有已发送的包被client确认后,server会发送FIN包给client,开始TCP四次挥手过程。
-
注意不管是关闭发送还是关闭接收,server端均向client端发送FIN报文。client 端收到FIN报文后,并不知道server端以何种方式shutdown,甚至不知道server端是shutdown还是close。
- client端收到FIN报文之后,详见下文叙述......
服务端调用close()
通过参数设置不同,调用close会出现如下A,B两种情况:
A. 向客户端发送一个RST报文,丢弃本地缓冲区的未读数据,关闭socket并释放相关资源,此种方式为强制关闭。(l_onoff为非0,l_linger为0,)
B. 向客户端发送一个FIN报文,收到client端FIN ACK后,进入了FIN_WAIT_2阶段,可参考TCP四次挥手过程,此种方式为优雅关闭。如果在l_linger的时间内仍未完成四次挥手,则强制关闭。( l_onoff 为非0,l_linger为非0)
FIN与RST
-
若server端发送FIN报文后没有收到client端的FIN ACK,会两次重传FIN报文,若一直收不到client端的FIN ACK,则会给client端发送RST信号,关闭socket并释放资源。(不同系统实现可能会不同)
-
client收到FIN信号后,再调用read函数会返回0。因为FIN的接收,表明client端以后再无数据可以接收,对方发来FIN,表明对方不在发送数据了。
(注意所有FIN及ACK报文均由操作系统自动完成发送接收)
-
client收到FIN后,会发送应答ack报文,表明收到server的FIN报文,server收到ack报文之后,就进入了FIN_WAIT_2阶段。
-
根据tcp协议,向一个 FIN_WAIT2 状态的 TCP写入数据是没有问题的,所以此时client可以调用write函数,写入到发送缓冲区,并由tcp连接,发送到server的接收缓冲区。由于server端已经关闭了socket,所以此时的server接收缓冲区的内容都被抛弃,同时server端返回RST给客户端。
-
client端如何知道已经接收到RST报文?
server发送RST报文后,并不等待从client端接收任何ack响应,直接关闭socket。而client端收到RST报文后,也不会产生任何响应。client端收到RST报文后,程序行为如下:
- 阻塞模型下,内核无法主动通知应用层出错,只有应用层主动调用read()或者write()这样的IO系统调用时,内核才会利用出错来通知应用层对端已经发送RST报文。
- 非阻塞模型下,select或者epoll会返回sockfd可读,应用层对其进行读取时,read()会报RST错误。
通过read write函数出错返回后,获取errno来确定对端是否发送RST信号。
- client收到RST报文后应如何处理?
client端收到RST信号后,如果调用read函数读取,则会返回RST错误。在已经产生RST错误的情况下,继续调用write,则会发生epipe错误。此时内核将向客户进程发送 SIGPIPE 信号,该信号默认会使进程终止,通常程序会异常退出(未处理SIGPIPE信号的情况下)。
在收到server发送RST报文的情况下,client端的任何read write都是毫无意义的。
作者:dacheng
链接:http://www.jianshu.com/p/eecab8d50697
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相关文章
- Android Support v4、v7、v13、v14、v17的区别和应用场景
- 032_磁盘格式时不同的分区label的区别
- Java反射关于getDeclaredMethods()和getMethods()的区别
- random.randint()与np.random.randint()的区别
- WebSocket、Socket、TCP、HTTP区别
- Linux 与 Unix 到底有啥区别和联系?
- WebSocket介绍,与Socket的区别
- C/C++项目中.h和.inc文件区别
- HTTP、TCP、UDP以及SOCKET之间的区别/联系
- EF5+MVC4系列(11)在主视图中用Html.RenderPartial调用分部视图(ViewDate传值);在主视图中按钮用ajax调用子action并在子action中使用return PartialView返回分布视图(return view ,return PartialView区别)
- Java取模(mod)与取余(rem)的区别
- java:网络编程(InetAddress,InetSocketAddress,URL,TCP(Socket与SeverSocket),TCP与UDP的区别)
- PHP 生成随机数rand()和mt_rand()的区别【转】
- Socket http和https的使用区别
- 前端开发中提到的“脚手架”到底指什么,CLI?gulp 和 gulp-cli有什么区别
- UrlConnection连接和Socket连接的区别
- linux之ext、ext1、ext2、ext3、ext4文件系统的区别及常用命令
- TCP与UDP的区别
- Linux中more和less的区别
- lib 和 dll 的区别、生成以及使用详解
- 区别Javascript中的Null与Undefined
- socket函数sendto与send的区别
- Socket PrintWriter 中 write() 与 print() 的区别
- 从缓冲上看阻塞与非阻塞socket在发送接收上的区别