1、正常情况下,调用close(),产生的其中一个效果就是发送FIN,只有双方都调用close(),才会出现正常的四次挥手。

2、如果是服务器,发起四次挥手是在关闭accept()返回的套接字,而不是socket()返回的套接字

3、Initiator=client,Receiver=server 情况:如果是服务器进入CLOSE_WAIT,而不发送FIN的话(也就是不调用close()),重新创建服务器需要等待一段时间bind才能成功,这个时间就是客户端FIN_WAIT_2的超时时间,超时后客户端发送RST给服务器。所以客户端close(),服务器必须也执行close()

4、主动调用 close() 一方才会进入 TIME_WAIT

5、调用shutdown()并不会启动四次挥手

断开为什么需要四次握手:

TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能到CLOSE状态

注:主动关闭一方会进入TIME_WAIT状态,以下假设Client是主动方

1、如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,保证能再次接收 FIN 并发送 ACK。(猜测: FIN超时时间应该小于MSL,否则Client等待2MSL,也可能接收不到FIN)

2、如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。

服务端为了解决这个TIME_WAIT问题,可选择的方式有三种:

Ø  服务器关闭的时候使用RST的方式(这是网友说的,我使用ESP8266做服务器,发送RST《发送RST的原因是调用 close() 时接收缓冲区还有未读完的数据》还是会等待2MSL)

 Ø  服务器close()发送RST而不是FIN

Ø  在创建socket,bind之前使能SO_REUSEADDR,然后close()(如果客户端断网了,假如服务器端没有keepalive(或者心跳包),服务器端没法知道客户端断网了,也就没法执行close()函数,而是傻傻继续等待客户端的数据)------- 适用于服务器不用检测客户端是否存在

Ø  如果使用keepalive,客户端断开网络(比如客户端被拔了网线),服务器的keepalive机制可以检测到,read()返回失败,服务器再次创建时不需要等待2MSL ------- 适用于服务器需要检测客户端是否存在

对于TIME_WAIT的插曲:

当建立一个TCP连接时,服务器端会继续用原有端口监听,同时用这个端口与客户端通信。而客户端默认情况下会使用一个随机端口与服务器端的监听端口通信。有时候,为了服务器端的安全性,我们需要对客户端进行验证,即限定某个IP某个特定端口的客户端。客户端可以使用bind来使用特定的端口。对于服务器端,当设置了SO_REUSEADDR选项时,它可以在2MSL内启动并listen成功。但是对于客户端,当使用bind并设置SO_REUSEADDR时,如果在2MSL内启动,虽然bind会成功,但是在windows平台上connect会失败。而在linux上则不存在这个问题。(我的实验平台:winxp, ubuntu7.10)

要解决windows平台的这个问题,可以设置SO_LINGER选项。SO_LINGER选项决定调用close时TCP的行为。SO_LINGER涉及到linger结构体,如果设置结构体中l_onoff为非0,l_linger为0,那么调用close时TCP连接会立刻断开,TCP不会将发送缓冲中未发送的数据发送,而是立即发送一个RST报文给对方,这个时候TCP连接就不会进入TIME_WAIT状态。如你所见,这样做虽然解决了问题,但是并不安全。通过以上方式设置SO_LINGER状态,等同于设置SO_DONTLINGER状态。

套接字 SO_LINGER 选项可以规定 close() 的行为:

l_onoff为0,则该选项关闭,l_linger的值被忽略,等于缺省情况,close立即返回;
l_onoff为非0,l_linger为0,则套接口关闭TCP连接时,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态; 
l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。如果套接口缓冲区中仍残留数据,进程将处于睡眠状态,直 到(a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)或(b)延迟时间到。此种情况下,应用程序检查close的返回值是非常重要的,如果在数据发送完并被确认前时间到,close将返回EWOULDBLOCK错误且套接口发送缓冲区中的任何数据都丢失。close的成功返回仅告诉我们发送的数据(和FIN)已由对方TCP确认,它并不能告诉我们对方应用进程是否已读了数据。如果套接口设为非阻塞的,它将不等待close完成

TCP ------ TCP四次挥手(断开连接)及断开过程的更多相关文章

  1. TCP采用四次挥手关闭连接如图所示为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

    tcp四次挥手,由于TCP连接是全双工的,因此每个方向都必须单独进行关闭. 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭.这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个 ...

  2. TCP的三次握手(建立连接)和四次挥手(关闭连接)

    参照: http://course.ccniit.com/CSTD/Linux/reference/files/018.PDF http://hi.baidu.com/raycomer/item/94 ...

  3. TCP的三次握手(建立连接)和四次挥手(关闭连接)(转)

    转自:(http://www.cnblogs.com/Jessy/p/3535612.html) 参照: http://course.ccniit.com/CSTD/Linux/reference/f ...

  4. 【转载】TCP的三次握手(建立连接)和四次挥手(关闭连接)

    建立连接: 理解:窗口和滑动窗口TCP的流量控制 TCP使用窗口机制进行流量控制 什么是窗口? 连接建立时,各端分配一块缓冲区用来存储接收的数据,并将缓冲区的尺寸发送给另一端 接收方发送的确认信息中包 ...

  5. TCP的三次握手(建立连接)与 四次挥手(关闭连接)

    一.TCP报文格式 TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图: TCP报文格式上图中有几个字段需要重点介绍下: (1)序号:Seq序号,占32位 ...

  6. tcp的三次握手及四次挥手(连接与中断流程)

    连接的三次握手: 1握.client向server发送连接请求,发送的报文是:syn=1,seq number=生成的随机数x .  这时client的状态是SYN_SEND 2握.server从sy ...

  7. 谈谈TCP的四次挥手

    “挥手”是为了终止连接,TCP四次挥手的流程图如下: (在socket编程中,可以由客户端或服务端进行close操作来进行) 下面的图是由客户端主动关闭连接 MSL是什么?最长报文段寿命 ------ ...

  8. 网络编程---scoket使用,七层协议,三次挥手建连接,四次挥手断连接

    目录 == 网络编程 == 软件开发架构 网络编程 互联网协议 TCP协议的工作原理 Socket == 网络编程 == 软件开发架构 开发软件 必须要开发一套 客户端与服务端 客户端与服务端的作用 ...

  9. tcp/ip四次挥手

    四次分手: 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭.这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接.收到一个 FIN只意味着这一方向上没有数据流动,一个 ...

  10. TCP的四次挥手

    由于TCP连接是全双工的,因此每个方向都必须单独进行关闭.这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接.收到一个 FIN只意味着这一方向上没有数据流动, 一个TCP连接 ...

随机推荐

  1. Android面试收集录 文件存储

    1.请描述Android SDK支持哪些文件存储技术? 使用SharePreferences保存key-value类型的数据 流文件存储(openFileOutput+openFileInput或Fi ...

  2. 初步学习pg_control文件之四

    接前文,初步学习pg_control文件之三  继续分析 何时出现 DB_SHUTDOWNING状态: 在正常的shutdown的时候,需要进行checkpoint,所以就在此处,设置pg_contr ...

  3. golang 小知识点记录

    获取url中的参数及输出到页面的几种方式 func SayHello(w http.ResponseWriter, req *http.Request) { req.Method //获取url的方法 ...

  4. vs2015-Cordova开发安卓应用环境搭建

    之前看到过用html5+css+js就可以开发跨平台的应用,然后发现vs2015里就有个Cordova项目所以就想试试,但并不是这么顺利.刚开始对安卓环境一点也不了解,就到处百度搜索.终于成功了. 首 ...

  5. Java Swing 图形界面开发(目录)

    Java Swing 图形界面开发(目录) 2017年05月30日 23:50:42 阅读数:5228 本文链接: http://blog.csdn.net/xietansheng/article/d ...

  6. Bash中使用MySQL导入导出CSV格式数据[转]

    转自: http://codingstandards.iteye.com/blog/604541 MySQL中导出CSV格式数据的SQL语句样本如下:   select * from test_inf ...

  7. 【数据库】 SQL SERVER 2014 实用新特性

    [数据库] SQL SERVER 2014 实用新特性 官方链接 一. 内存优化表 大幅提高数据库性能,不过目前没有窗口化设计只能写语句 二. 索引增强

  8. vue3.0 部署的基础流程

    1.创建vue.config.js 主要是负责做设置的 2.修改vue.config.js 参考官方说明: 注意:对于本地开发的同学要注意,你之前在处理网络请求时是在8080端口下请求,现在如果换成了 ...

  9. Vm-Ubuntu下配置Qt开发环境

    在昨天的Ubuntu换降下,安装Qt发现编译的时候是缺少opengl的 奈何找了好多方式都无法安装opengl 今天看到另一位大神写的,才发下自己找的还是有问题 大神帖子网址:http://blog. ...

  10. 接口测试工具postman(三)添加断言

    每个用例执行完成后,可以通过添加断言来判断返回结果是否正确,即表示用例执行是否成功. 官方说明文档:https://learning.getpostman.com/docs/postman/scrip ...