TCP协议连接建立时3次握手的过程4次结束连接_hankwangwang的博客-程序员信息网

技术标签: tcp  Linux开发c/c++  平台  linux  服务器  socket  windows  

协议连接建立时3次握手的过程4次结束连接
 
TCP协议连接建立时3次握手的过程。

简述TCP协议连接建立时3次握手的过程。

根据TCP头部,说明下列3个包在连接建立过程中的次序.

0020        00 50 83 aa 46 49 3e dd 33 96 37 a3 a0 12  ...P..FI>.3.7...

0030   16 a0 c4 c0 00 00 02 04 05 b4 04 02 08 0a d7 9b  ................

0040   62 b7 00 56 4a 2a 01 03 03 02                    b..VJ*....   1

0020        83 aa 00 50 33 96 37 a2 00 00 00 00 a0 02  .....P3.7.......

0030   16 d0 84 1d 00 00 02 04 05 b4 04 02 08 0a 00 56  ...............V

0040   4a 2a 00 00 00 00 01 03 03 00                    J*........    2

0020        83 aa 00 50 33 96 37 a3 46 49 3e de 80 10  .....P3.7.FI>...

0030   16 d0 f3 4b 00 00 01 01 08 0a 00 56 4a 36 d7 9b  ...K.......VJ6..

0040   62 b7                                            b.    3

解:

TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。

1)是第二次握手,flags位上为12,二进制是0001 0010,即表示有synack.

2)是第一次握手,flags位上为02,二进制是0000 0010,即表示有syn没有ack

3)是第三次握手,flags位上为10,二进制是0001 0000,即表示有ack没有syn

该连接访问的是80端口,是为HTTPHyperText Transport Protocol,超文本传输协议)开放的,

第一次握手:建立连接时,客户端发送syn(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYNack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;


第三次握手:客户端收到服务器的SYNACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。


完成三次握手,客户端与服务器开始传送数据。

tcp-断开连接:

主要部分,四次握手:

断开连接其实从我的角度看不区分客户端和服务器端,任何一方都可以调用close(or closesocket)之类
的函数开始主动终止一个连接。这里先暂时说正常情况。当调用close函数断开一个连接时,主动断开的
一方发送FIN(finish报文给对方。有了之前的经验,我想你应该明白我说的FIN报文时什么东西。也就是
一个设置了FIN标志位的报文段。FIN报文也可能附加用户数据,如果这一方还有数据要发送时,将数据附
加到这个FIN报文时完全正常的。之后你会看到,这种附加报文还会有很多,例如ACK报文。我们所要把握
的原则是,TCP肯定会力所能及地达到最大效率,所以你能够想到的优化方法,我想TCP都会想到。

当被动关闭的一方收到FIN报文时,它会发送ACK确认报文(对于ACK这个东西你应该很熟悉了)。这里有个
东西要注意,因为TCP是双工的,也就是说,你可以想象一对TCP连接上有两条数据通路。当发送FIN报文
时,意思是说,发送FIN的一端就不能发送数据,也就是关闭了其中一条数据通路。被动关闭的一端发送
了ACK后,应用层通常就会检测到这个连接即将断开,然后被动断开的应用层调用close关闭连接。

我可以告诉你,一旦当你调用close(or closesocket),这一端就会发送FIN报文。也就是说,现在被动
关闭的一端也发送FIN给主动关闭端。有时候,被动关闭端会将ACK和FIN两个报文合在一起发送。主动
关闭端收到FIN后也发送ACK,然后整个连接关闭(事实上还没完全关闭,只是关闭需要交换的报文发送
完毕),四次握手完成。如你所见,因为被动关闭端可能会将ACK和FIN合到一起发送,所以这也算不上
严格的四次握手---四个报文段。

在前面的文章中,我一直没提TCP的状态转换。在这里我还是在犹豫是不是该将那张四处通用的图拿出来,
不过,这里我只给出断开连接时的状态转换图,摘自<The TCP/IP Guide>:

tcpclose

给出一个正常关闭时的windump信息:

14:00:38.819856 IP cd-zhangmin.1748 > 220.181.37.55.80: F 1:1(0) ack 1 win 65535
14:00:38.863989 IP 220.181.37.55.80 > cd-zhangmin.1748: F 1:1(0) ack 2 win 2920
14:00:38.864412 IP cd-zhangmin.1748 > 220.181.37.55.80: . ack 2 win 65535

补充细节:

关于以上的四次握手,我补充下细节:
1. 默认情况下(不改变socket选项),当你调用close( or closesocket,以下说close不再重复)时,如果
发送缓冲中还有数据,TCP会继续把数据发送完。


2. 发送了FIN只是表示这端不能继续发送数据(应用层不能再调用send发送),但是还可以接收数据。


3. 应用层如何知道对端关闭?通常,在最简单的阻塞模型中,当你调用recv时,如果返回0,则表示对端
关闭。在这个时候通常的做法就是也调用close,那么TCP层就发送FIN,继续完成四次握手。如果你不调用
close,那么对端就会处于FIN_WAIT_2状态,而本端则会处于CLOSE_WAIT状态。这个可以写代码试试。


4. 在很多时候,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分钟),即使两端的应用程序结束。你可以写代码试试,然后用netstat查看下。

为什么需要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选项来解决,不过不知道这个选项是否对于所有平台都有效。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/eroswang/article/details/3080217

智能推荐

文献类型_四荒的博客-程序员信息网

一、一次文献一次文献指以作者本人的研究成果为依据而创作的原始文献,如期刊论文、研究报告、专利说明书、会议论文等。一次文献数量庞大、分散在各种期刊、媒体、会议论文集、图书、连续性出版物、特种文献之中,所以寻找困难。1)论著1.“论著”指的是“议论性著作”,是医学论文体裁中常见的一种表现形式,具有特定的概念。2.论著是作者将自己的科研、临床、教学的成果、经验、体会,以严密的逻辑论证、规...

JAVA ScheduledExecutorService定时器写法_AoLuo93的博客-程序员信息网

import java.util.concurrent.*;public class Test { public static void main(String[] args) { ScheduledExecutorService pool = Executors.newScheduledThreadPool(10); Runnable tt= (...

打叉图标html,网页上一些图标和按钮显示为叉为什么_weixin_40004659的博客-程序员信息网

原因:1、网速过慢导致。2、浏览器设置问题。3、系统问题导致。解决方法:1、检查网速传输速度,可以打开“运行”--输入CMD,在命令提示符中输入ipconfig /release重新释放缓存,之后输入ipconfig /renew重新连接。2、在浏览器中点击“工具”--Internet选项-高级--多媒体--显示图片,勾选“显示图片”,确认后刷新页面。3、如果是系统问题,可尝试以下方法。1)使用 ...

keras报错:ValueError: Layer model_1 was called with an input that isn’t a symbolic tensor_Stanford6的博客-程序员信息网

keras报错:ValueError: Layer model_1 was called with an input that isn’t a symbolic tensor后面还有错误Received type: &lt;class 'numpy.ndarray'&gt;All inputs to the layer should be tensors.解决办法例如搭建了自定义的网络模型self.discriminator_layer1, 在调用时不能忘了加.predictself.dis

以太坊DApp开发:web3.js与智能合约交互_weixin_43250732的博客-程序员信息网

前言本文参考:https://blog.csdn.net/pony_maggie/article/details/79685942实现了最终的结果,并在其基础上做出了更加详细的说明与部分细节的完善,供读者参考。环境准备ubuntu 14.0.4(16.0.4), 64位还需要安装以太坊相关的环境:nodejstrufflesoliditytestrpc具体安装步骤可以参考...

出现UnboundLocalError: local variable 'a' referenced before assignment异常的情况与解决方法_DansonC的博客-程序员信息网

出现UnboundLocalError: local variable ‘a’ referenced before assignment异常的情况与解决方法字面意思:局部变量赋值前被引用原因:局部变量与全局变量同名例:a = 1def func(): a += 1 print(a)func()解决方法:1.使局部变量与全局变量不同名a = 1def func...

随便推点

分布式架构——Gossip 协议详解_hebeind100的博客-程序员信息网

Database Maintenance》中被提出。原本用于分布式数据库中节点同步数据使用,后被广泛用于数据库复制、信息扩散、集群成员身份确认、故障探测等。 Gossip协议是基于六度分隔理论(Six Degrees of Separation)哲学的体现,简单的来说,一个人通过6个中间人可以认识世界任何人。数学公式是:n表示复杂度,N表示人的总数,W表示每个人的联系宽度。依据邓巴数,即每个人认识150人,其六度就是1506 =11,390,625,000,000(约11.4万亿)。 

JVM垃圾收集器:CMS与G1_Awille的博客-程序员信息网

                                         JVM垃圾收集器:CMS与G1 一、CMS垃圾收集器CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。基于“标记-清除”算法实现:包括步骤:1、CMS intial mark(初始标记):标记GC Roots能直接关联到的对象,速度很快...

JQ获取当前时间(日期)YY-MM-DD hh:mm:ss_IT牛男_Edward的博客-程序员信息网_jquery获取当前日期yyyymmdd

在实际项目中,有时候需要当前时间和过去时间做对比,因此找到了一种方法,经检测可用//获取当前时间  格式为2018-08-17 20:12:32    function getNowFormatDate() {    var date = new Date();    var seperator1 = &quot;-&quot;;    var seperator2 = &quot;:&quot;;    var mont...

Cesium地图反遮罩_cesium 遮罩_Dani05的博客-程序员信息网

实现的思路是面带洞,添加两个半圆polygon覆盖整个地球,在有需要突出提亮部分的polygon中使用holes属性挖空,最后添加polyline高亮边界范围。addMasker(viewer) { var point = []; //point数组中放你自己提亮范围的边界经纬度 for (let i = 0; i &lt; Test.features[0].geometry.coordinates[0][0].length; i++) { ...

(debug)keras 报错:UserWarning: Update your `Model` call to the Keras 2 API: `Model(inputs=Tensor(“in.._weixin_44444347的博客-程序员信息网

如题,从keras导入model,使用时候出错。方法是把input改成inputs原来model_final = Model(input = vggmodel.input, output = predictions)修改后model_final = Model(inputs = vggmodel.input, outputs = predictions)

推荐文章

热门文章

相关标签