TCP/IP的3次握手和4次握手
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接,如图1所示。
(1) 第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。
(2) 第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。
(3) 第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
这个问题可以参考《unix 网络编程》(第三版,2.7 TIME_WAIT状态)。
TIME_WAIT状态由两个存在的理由。
(1)可靠的实现TCP全双工链接的终止。
这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。
(2)允许老的重复的分节在网络中消逝。
假设在12.106.32.254的1500端口和206.168.1.112.219的21端口之间有一个TCP连接。我们关闭这个链接,过一段时间后在相同的IP地址和端口建立另一个连接。后一个链接成为前一个的化身。因为它们的IP地址和端口号都相同。TCP必须防止来自某一个连接的老的重复分组在连接已经终止后再现,从而被误解成属于同一链接的某一个某一个新的化身。为做到这一点,TCP将不给处于TIME_WAIT状态的链接发起新的化身。既然TIME_WAIT状态的持续时间是MSL的2倍,这就足以让某个方向上的分组最多存活msl秒即被丢弃,另一个方向上的应答最多存活msl秒也被丢弃。通过实施这个规则,我们就能保证每成功建立一个TCP连接时。来自该链接先前化身的重复分组都已经在网络中消逝了。
3. 为什么不能用两次握手进行连接?
我们知道,3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
补充:
a. 默认情况下(不改变socket选项),当你调用close( or closesocket,以下说close不再重复)时,如果发送缓冲中还有数据,TCP会继续把数据发送完。
b. 发送了FIN只是表示这端不能继续发送数据(应用层不能再调用send发送),但是还可以接收数据。
c. 应用层如何知道对端关闭?通常,在最简单的阻塞模型中,当你调用recv时,如果返回0,则表示对端关闭。在这个时候通常的做法就是也调用close,那么TCP层就发送FIN,继续完成四次握手。如果你不调用close,那么对端就会处于FIN_WAIT_2状态,而本端则会处于CLOSE_WAIT状态。这个可以写代码试试。
d. 在很多时候,TCP连接的断开都会由TCP层自动进行,例如你CTRL+C终止你的程序,TCP连接依然会正常关闭,你可以写代码试试。
插曲:
特别的TIME_WAIT状态:
从以上TCP连接关闭的状态转换图可以看出,主动关闭的一方在发送完对对方FIN报文的确认(ACK)报文后,会进入TIME_WAIT状态。TIME_WAIT状态也称为2MSL状态。
什么是2MSL?MSL即Maximum Segment Lifetime,也就是报文最大生存时间,引用《TCP/IP详解》中的话:“它(MSL)是任何报文段被丢弃前在网络内的最长时间。”那么,2MSL也就是这个时间的2倍。其实我觉得没必要把这个MSL的确切含义搞明白,你所需要明白的是,当TCP连接完成四个报文段的交换时,主动关闭的一方将继续等待一定时间(2-4分钟),即使两端的应用程序结束。你可以写代码试试,然后用setstat查看下。
为什么需要2MSL?根据《TCP/IP详解》和《The TCP/IP Guide》中的说法,有两个原因:
其一,保证发送的ACK会成功发送到对方,如何保证?我觉得可能是通过超时计时器发送。这个就很难用代码演示了。
其二,报文可能会被混淆,意思是说,其他时候的连接可能会被当作本次的连接。直接引用《The TCP/IP Guide》的说法:The second is to provide a “buffering period” between the end of this connection and any subsequent ones. If not for this period, it is possible that packets from different connections could
be mixed, creating confusion.
TIME_WAIT状态所带来的影响:
当某个连接的一端处于TIME_WAIT状态时,该连接将不能再被使用。事实上,对于我们比较有现实意义的是,这个端口将不能再被使用。某个端口处于TIME_WAIT状态(其实应该是这个连接)时,这意味着这个TCP连接并没有断开(完全断开),那么,如果你bind这个端口,就会失败。对于服务器而言,如果服务器突然crash掉了,那么它将无法再2MSL内重新启动,因为bind会失败。解决这个问题的一个方法就是设置socket的SO_REUSEADDR选项。这个选项意味着你可以重用一个地址。
对于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状态。
断开连接时的意外:
这个算不上断开连接时的意外,当TCP连接发生一些物理上的意外情况时,例如网线断开,linux上的TCP实现会依然认为该连接有效,而windows则会在一定时间后返回错误信息。这似乎可以通过设置SO_KEEPALIVE选项来解决,不过不知道这个选项是否对于所有平台都有效。
转载自:TCP3次握手/4次握手
作者的专栏包括:
TCP/IP的3次握手和4次握手的更多相关文章
- TCP/IP 协议栈4层结构及3次握手4次挥手
TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...
- TCP/IP的三次握手协议
关于TCP/IP的三次握手协议,这篇文章中有详细的介绍,很通俗易懂,什么时候忘了,都可以过来瞧两眼,保证很快就明白了. 首先TCP/IP协议分为三个阶段:建立连接(握手阶段),数据传输阶段,连接终止阶 ...
- 需要知道的TCP/IP三次握手
TCP/IP三次握手是TCP协议中比较重要的一个知识点,但是在很多博客中看到的三次握手的过程图很多都不是很正确.我在google找到了一篇写的非常不错的介绍TCP/IP技术文章期中就有三次握手的讲解, ...
- TCP/IP协议三次握手与四次握手流程解析
原文链接地址:http://www.2cto.com/net/201310/251896.html TCP/IP协议三次握手与四次握手流程解析 TCP/IP协议的详细信息参看<TCP/IP协议详 ...
- TCP/IP三次握手和HTTP过程
1.TCP连接 手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接.TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在"无差别&qu ...
- TCP\IP三次握手连接,四次握手断开分析
TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标 ...
- TCP/IP协议 三次握手与四次挥手
一.TCP报文格式 TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图: 图1 TCP报文格式 上图中有几个字段需要重点介绍下: (1)序号 ...
- 关于TCP/IP的三次握手和四次挥手解释
TCP协议三次握手过程分析 TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: ...
- (转载)TCP/IP的三次握手与四次挥手
TCP三次握手 所谓三次握手(Three-way Handshake),是指建立一个TCP连接时,需要客户端和服务器总共发送3个包. 三次握手的目的是连接服务器指定端口,建立TCP连接,并同步 ...
- TCP/IP协议握手过程详解
1,建立连接 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接,如图1所示. (1)第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SE ...
随机推荐
- QT5的exe的发布
直接release的exe文件需要很多dll关联,一个一个找又太麻烦. 其实QT5带有一个 windeployqt 工具 Qt Widgets Application可执行程序发布方式 首先用 QtC ...
- c的详细学习(1)C语言概述
本节用来简要介绍c语言. (1)C语言的特点: C语言是一种集汇编语言及高级语言为一身的,面向过程的结构化和模块化的程序设计语言. 特点: 兼具高级语言与低级语言的双重能力.C语言允许 ...
- ubuntu14.04 在自带python2.7上安装python3.3.5 可以用但是有问题
一开始写的时候并没有发现这么安装有问题,后来发现问题也不想删了,当个教训,如果想安装从python自带版本换别的版本的话就别接着看了,这么安装有问题.需要进行配置,但是我还不会.其实下面只是差了一步配 ...
- 简单做出HTML5翻页效果文字特效
之前在网上看到一款比较有新意的HTML5文字特效,文字效果是当鼠标滑过是出现翻开折叠的效果,类似书本翻页.于是我兴致勃勃的点开源码看了一下,发现其实实现也挺简单的,主要利用了CSS3的transfor ...
- JS饼状图表数据分布插件
在线演示 本地下载
- Maze迷宫问题(求最优解)
迷宫地形我们可以通过读文件的形式,通过已知入口逐个遍历坐标寻找通路. 文件如图: 每个坐标的位置用结构体来记录: struct Pos //位置坐标 { int _row; int _col; }; ...
- if-else 与 switch-case语句
if语句就是起一个判断作用,在c语言中有三种表达形式:1.if(表达式)语句:pl. if(x==y)printf("%d",x); //* "== ...
- Android蓝牙串口通讯【转】
本文转载自:http://blog.sina.com.cn/s/blog_631e3f2601012ixi.html Android蓝牙串口通讯 闲着无聊玩起了Android蓝牙模块与单片机蓝牙模块的 ...
- 在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务【转】
本文转载自:http://blog.csdn.net/luoshengyang/article/details/6578352 在数字科技日新月异的今天,软件和硬件的完美结合,造就了智能移动设备的流行 ...
- 剑指offer——圆圈中最后剩下的数字
1.如果通过环形列表去模拟圆圈的话,最后时间复杂度为O(mn),而且还需要一个辅助链表来模拟圆圈,空间复杂度为O(n). 2.通过找出递推公式的方法,求得递推公式为 时间复杂度为O(n),空间复杂度为 ...