TCP连接关闭总结
由于涉及面太广,只作简单整理,有兴趣的可参考《UNIX Networking Programming》volum 1, Section 5.7, 5.12, 5.14, 5.15, 6.6 以及7.5 SO_LINGER选项。
以一个简单的echo服务器为例,客户端从标准输入读入字符,发送给服务器,服务器收到后再原样返回,客户端收到后打印到标准输出。
那么,关于套接字的关闭有以下几种情形:
1,客户端关闭连接:
1.1,客户端调用close()
1.2,客户端进程关闭
1.3,客户端调用shutdown()
1.4,客户端调用close()+SO_LINGER选项
1.5,客户端崩溃
2,服务器关闭连接:
2.1,服务器调用close()
2.2,服务器进程关闭
2.3,服务器崩溃
2.4,服务器崩溃+SO_KEEPALIVE选项
============================分割线===============================
1.1与1.2等价,就算客户端进程关闭,系统内核也会自动close(socket),且注意,当socket引用为0时才会真正调用close(),close()总是立即返回的,然后由系统尝试发送完内核缓冲区内的所有数据,接着才发送FIN。
说道这里,不得不谈谈TCP连接关闭的四次握手。可以看成是2组FIN, ACK。主动关闭的一方先发送FIN,收到ACK后,进入FIN_WAIT2状态,此时也叫做“半关闭”状态,特别须要注意的是,此时客户端套接字依然可以接收数据包,但是不能发送数据包。 被动关闭的一方,此时收到FIN了,一般情况下都是由于read(socket)返回0,然后得知对方关闭,close(socket)后,另外一组FIN,ACK随之产生,此时主动方进入TIME_WAIT状态。即四次握手完成。
以上即是正常情况下连接关闭的情形。
再看看1.3,shutdown()与close()主要有3点区别:
shutdown()不理会引用计数与内核缓冲区内剩余待发数据包,直接发送FIN;
shutdown()可以只关闭套接字某个方向的连接,例如关闭发送,关闭接收,或者2者都关闭;
实际上shutdown(write)后,就是上面说的半关闭情形,依然可以完成四次握手。
再看看1.4,为什么要设置SO_LINGER呢
SO_LINGER的目的就是改变close()的默认行为,可以决定close()在哪个状态返回,或者让套接字立即发送RST,从而没有FIN的发送。接收方返回ECONNRESET错误,连接直接关闭。
再来总结下1.1-1.4,这么多关闭连接的方式,那么什么方式才是最好的呢?
择优选择的方式当然是考虑最恶劣的情况,对方主机崩溃或网络故障导致数据包传输停滞。
RST不用考虑了,直接TIME_WAIT状态都没,如果有网络故障,可能下次创建的套接字还会接收到已经被销毁的套接字的数据报。
close()不能保证对方一定收到FIN。
close()+SO_LINGER虽然能控制close()在收到ACK后返回,依然不能保证四次握手完成。
shutdown()先进入半关闭状态,再调用read(),返回0(收到对方FIN)则说明四次握手正常进行,此为最优方式。
其实仔细想想,一般情况也不用这么麻烦,拿网游服务器来说,客户端close()后,就算服务器不知道,那么这种情况归为1.5讨论;如果是服务端close()而客户端不知道,那么归为2.3讨论。总之都有解决办法。。
现在再讨论1.5,很简单,服务端加入链路异常检测机制即可,这也是所有大型TCP服务器必备的机制,定时发送小数据包检测客户端是否有异常退出。
=============================分割线==============================
服务器关闭连接方面:
2.1,2.2等价,一般情况下也与1.1,1.2等价,只是主动关闭方是服务器了。
但是,在我们讨论的例子里,客户端要从标准输入读字符,这是阻塞方式,服务端关闭连接后,客户端无法知道,因为它阻塞在标准输入了,当我们再次输入字符,并发送,收到FIN或RST,此时客户端才关闭。总之,客户端由于某种原因,不能及时调用read(),所以无法得知服务器关闭了连接。
2.3,服务器崩溃,客户端由于一直收不到ACK,会一直尝试发送数据,标准socket大概是9分钟后才会返回错误。
2.3,服务器崩溃,客户端又长时间与服务器没有数据交互,此时设置SO_KEEPALIVE选项可得知。
=============================分割线=============================
后记:网络是门复杂的学问,由此TCP连接的关闭可见一斑。普通程序员通常不会考虑这么细致,但是我相信这些问题一直困扰着他们。
补充说明:经试验,在Windows平台,1.2 2.2情况等同于close()+SO_LINGER选项直接发送RST,可能由于系统必须及时清理资源吧,这点与linux是不同的,有兴趣的可以试试。。
TCP连接关闭总结的更多相关文章
- socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题
Tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下, send函数的过程是将应用程序请求发送的数 ...
- [转]socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题
Tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下, send函数的过程是将应用程序请求发送的数 ...
- Linux 内核协议栈之TCP连接关闭
Close行为: 当应用程序在调用close()函数关闭TCP连接时,Linux内核的默认行为是将套接口发送队列里的原有数据(比如之前残留的数据)以及新加入 的数据(比如函数close()产生的FIN ...
- TCP 连接关闭及TIME_WAIT探究
这里主要记录一下TCP连接在关闭的时刻,有哪些细节问题.方便在以后的程序设计中能够注意这些细节, 以避免出现这些错误.首先我们来看一下TCP的状态转换图.如<unix网络编程>卷一所示如下 ...
- TCP连接性能指标之TCP关闭过程(四次挥手)
TCP关闭过程(四次挥手): ESTABLISHED: 当前建立连接状态 CLOSE_WAIT:Server端收到来自Client端的FIN包后,发送ACK回Client端,进入CLOSE_WAIT ...
- 我为 Netty 贡献源码 | 且看 Netty 如何应对 TCP 连接的正常关闭,异常关闭,半关闭场景
欢迎关注公众号:bin的技术小屋,本文图片加载不出来的话可查看公众号原文 本系列Netty源码解析文章基于 4.1.56.Final版本 写在前面..... 本文是笔者肉眼盯 Bug 系列的第三弹,前 ...
- TCP连接——爱的传声筒
TCP连接——爱的传声筒 TCP通信最重要的特征是:有序(ordering)和可靠(reliable).有序是通过将文本流分段并编号实现的.可靠是通过ACK回复和重复发送(retransmission ...
- 关于Kafka producer管理TCP连接的讨论
在Kafka中,TCP连接的管理交由底层的Selector类(org.apache.kafka.common.network)来维护.Selector类定义了很多数据结构,其中最核心的当属java.n ...
- mysql服务器,大量tcp连接状态TIME_WAIT
今天早上,java应用中发现too many open files,检查了下使用的连接数发现基本上在两三百左右,mysql打开的文件数也就几百左右,再看所有tcp连接,发现3306的连接有4000多, ...
随机推荐
- java自定义注释及其信息提取
转自:https://xuwenjin666.iteye.com/blog/1637247 1. 自定义注解 import java.lang.annotation.Retention; import ...
- 使用Hybris commerce的promotion rule进行促销活动
backoffice Marketing菜单下面,新建一个Promotion rule: Promotion的条件,设置成针对商城里所有的数码相机: Promotion触发条件在Conditions区 ...
- zookeeper介绍(4)zookeeper的完整分布式
参考: zookeeper的单机和伪分布式教程请参考:zookeeper介绍(1)zookeeper介绍与安装 Zookeeper的完整分布式集群搭建: 准备好三台centos主机:(在这我使用的是z ...
- 关于MySQL数据库编码修复相关问题
本篇主要是本人在实际开发过程中遇到的MySQL字符编码等bug修复相关问题. 在使用下列语句在执行数据库表通过flask-sqlacodegen 进行ORM映射成模型类的时候发生的bug: flask ...
- 在CentOS 7上修改主机名的方法
这次我们来讲解一下如何在CentOS 7环境上修改主机名 1.从VMware上登录CentOS 7的虚拟机,并以root用户登录. 2.查看未修改前的主机名 1>.我们可以通过文件hostnam ...
- javascript原生图片懒加载
一,原生javascript图片懒加载 1. 使用方法,例如 // 要绑定的图片地址 <img data-src={url} alt=" "> 2. 在页面中引入下列原 ...
- 项目Alpha冲刺——集合
作业描述 课程: 软件工程1916|W(福州大学) 作业要求: 项目Alpha冲刺(团队) 团队名称: 火鸡堂 作业目标: 完成项目Alpha冲刺 团队信息 队名:火鸡堂 队员学号 队员姓名 博客地址 ...
- java构建简单的HTTP服务器
使用Java技术构建Web应用时, 我们通常离不开tomcat和jetty之类的servlet容器,这些Web服务器功能强大,性能强劲,深受欢迎,是运行大型Web应用的必备神器. 虽然Java的设计初 ...
- 自定义express中间件
const http = require('http') class LikeExpress { constructor() { this.middleList = [] this.routes = ...
- Bootstrap内栅格布局,表格,按钮,图片的个人总结
栅格布局: container,固定宽度的容器. container-fluid,百分百宽度的容器. 使用行(row)在水平方向上创建一组列(colmun). 每一行中最多能够包含12列,超出的列则另 ...