活久见!TCP两次挥手,你见过吗?那四次握手呢?

来源:QQ快报
责任编辑:李志喜
字体:

我们都知道,TCP是个面向连接的、可靠的、基于字节流的传输层通信协议。

TCP是什么

那这里面提到的"面向连接",意味着需要 建立连接,使用连接,释放连接。

建立连接是指我们熟知的TCP三次握手

使用连接,则是通过一发送、一确认的形式,进行数据传输

还有就是释放连接,也就是我们常见的TCP四次挥手

TCP四次挥手大家应该比较了解了,但大家见过三次挥手吗?还有两次挥手呢?

都见过?那四次握手呢?

今天这个话题,不想只是猎奇,也不想搞冷知识。

我们从四次挥手开始说起,搞点实用的知识点。

TCP四次挥手

简单回顾下TCP四次挥手。

TCP四次挥手

正常情况下。只要数据传输完了,不管是客户端还是服务端,都可以主动发起四次挥手,释放连接。

就跟上图画的一样,假设,这次四次挥手是由客户端主动发起的,那它就是主动方。服务器是被动接收客户端的挥手请求的,叫被动方

客户端和服务器,一开始,都是处于状态。

第一次挥手:一般情况下,主动方执行或 方法,会发个出来,表示"我不再发送数据了"。

第二次挥手:在收到主动方的报文后,被动方立马回应一个,意思是"我收到你的FIN了,也知道你不再发数据了"。

上面提到的是主动方不再发送数据了。但如果这时候,被动方还有数据要发,那就继续发。注意,虽然第二次和第三次挥手之间,被动方是能发数据到主动方的,但主动方能不能正常收就不一定了,这个待会说。

第三次挥手:在被动方在感知到第二次挥手之后,会做了一系列的收尾工作,最后也调用一个 , 这时候就会发出第三次挥手的 。

第四次挥手:主动方回一个,意思是收到了。

其中第一次挥手和第三次挥手,都是我们在应用程序中主动触发的(比如调用方法),也就是我们平时写代码需要关注的地方。

第二和第四次挥手,都是内核协议栈自动帮我们完成的,我们写代码的时候碰不到这地方,因此也不需要太关心。

另外不管是主动还是被动,每方发出了一个 和一个 。也收到了一个 和一个 。这一点大家关注下,待会还会提到。

FIN一定要程序执行close()或shutdown()才能发出吗?

不一定。一般情况下,通过对执行 或 方法会发出。但实际上,只要应用程序退出,不管是主动退出,还是被动退出(因为一些莫名其妙的原因被了),都会发出 。

FIN 是指"我不再发送数据",因此 关闭读不会给对方发FIN, 关闭写才会发FIN。

如果机器上FIN-WAIT-2状态特别多,是为什么

根据上面的四次挥手图,可以看出,是主动方那边的状态。

处于这个状态的程序,一直在等第三次挥手的。而第三次挥手需要由被动方在代码里执行 发出。

因此当机器上状态特别多,那一般来说,另外一台机器上会有大量的 。需要检查有大量的 的那台机器,为什么迟迟不愿调用关闭连接。

所以,如果机器上状态特别多,一般是因为对端一直不执行方法发出第三次挥手。

FIN-WAIT-2特别多的原因

主动方在close之后收到的数据,会怎么处理

之前写的一篇文章《代码执行send成功后,数据就发出去了吗?》中,从源码的角度提到了,一般情况下,程序主动执行的时候;

如果当前连接对应的的接收缓冲区有数据,会发。

如果发送缓冲区有数据,那会等待发送完,再发第一次挥手的。

大家知道,TCP是全双工通信,意思是发送数据的同时,还可以接收数据。

的含义是,此时要同时关闭发送和接收消息的功能。

也就是说,虽然理论上,第二次和第三次挥手之间,被动方是可以传数据给主动方的。

但如果 主动方的四次挥手是通过 触发的,那主动方是不会去收这个消息的。而且还会回一个 。直接结束掉这次连接。

close()触发TCP四次挥手

第二第三次挥手之间,不能传输数据吗?

也不是。前面提到的含义是,要同时关闭发送和接收消息的功能。

那如果能做到只关闭发送消息不关闭接收消息的功能,那就能继续收消息了。这种 的功能,通过调用 方法就能做到。

其中 howto 为断开方式。有以下取值:

SHUT_RD:关闭读。这时应用层不应该再尝试接收数据,内核协议栈中就算接收缓冲区收到数据也会被丢弃。

SHUT_WR:关闭写。如果发送缓冲区中还有数据没发,会将将数据传递到目标主机。

SHUT_RDWR:关闭读和写。相当于了。

shutdown触发的TCP四次挥手

怎么知道对端socket执行了close还是shutdown

不管主动关闭方调用的是还是,对于被动方来说,收到的就只有一个。

被动关闭方就懵了,"我怎么知道对方让不让我继续发数据?"

其实,大可不必纠结,该发就发。

第二次挥手和第三次挥手之间,如果被动关闭方想发数据,那么在代码层面上,就是执行了 方法。

会把数据拷贝到本机的发送缓冲区。如果发送缓冲区没出问题,都能拷贝进去,所以正常情况下,一般都会返回成功。

![tcp_sendmsg 逻辑](https://cdn.jsdelivr.net/gh/xiaobaiTech/image/tcp_sendmsg 逻辑.png)

然后被动方内核协议栈会把数据发给主动关闭方。

如果上一次主动关闭方调用的是。那此时,主动关闭方不再发送消息,但能接收被动方的消息,一切如常,皆大欢喜。

如果上一次主动关闭方调用的是。那主动方在收到被动方的数据后会直接丢弃,然后回一个。

针对第二种情况。

被动方内核协议栈收到了,会把连接关闭。但内核连接关闭了,应用层也不知道(除非被通知)。

此时被动方应用层接下来的操作,无非就是读或写

如果是读,则会返回的报错,也就是我们常见的。

如果是写,那么程序会产生信号,应用层代码可以捕获并处理信号,如果不处理,则默认情况下进程会终止,异常退出。

总结一下,当被动关闭方 返回时,说明主动方通过 或 发起了第一次挥手。

如果此时被动方执行两次

第一次, 一般会成功返回。

第二次时。如果主动方是通过 发起的第一次挥手,那此时还是会成功。如果主动方通过 发起的第一次挥手,那此时会产生信号,进程默认会终止,异常退出。不想异常退出的话,记得捕获处理这个信号。

如果被动方一直不发第三次挥手,会怎么样

第三次挥手,是由被动方主动触发的,比如调用。

如果由于代码错误或者其他一些原因,被动方就是不执行第三次挥手。

这时候,主动方会根据自身第一次挥手的时候用的是 还是 ,有不同的行为表现。

如果是 ,说明主动方其实只关闭了写,但还可以读,此时会一直处于 , 死等被动方的第三次挥手。

如果是 , 说明主动方读写都关闭了,这时候会处于 一段时间,这个时间由 控制,一般是 ,这个值正好跟一样 。超过这段时间之后,状态不会变成 `TIME-WAIT`,而是直接变成`CLOSED`。

一直不发第三次挥手的情况

TCP三次挥手

四次挥手聊完了,那有没有可能出现三次挥手?

是可能的。

我们知道,TCP四次挥手里,第二次和第三次挥手之间,是有可能有数据传输的。第三次挥手的目的是为了告诉主动方,"被动方没有数据要发了"。

所以,在第一次挥手之后,如果被动方没有数据要发给主动方。第二和第三次挥手是有可能合并传输的。这样就出现了三次挥手。

TCP三次挥手

如果有数据要发,就不能是三次挥手了吗

上面提到的是没有数据要发的情况,如果第二、第三次挥手之间有数据要发,就不可能变成三次挥手了吗?

并不是。TCP中还有个特性叫延迟确认。可以简单理解为:接收方收到数据以后不需要立刻马上回复ACK确认包。

在此基础上,不是每一次发送数据包都能对应收到一个 确认包,因为接收方可以合并确认。

而这个合并确认,放在四次挥手里,可以把第二次挥手、第三次挥手,以及他们之间的数据传输都合并在一起发送。因此也就出现了三次挥手。

TCP三次挥手延迟确认

TCP两次挥手

前面在四次挥手中提到,关闭的时候双方都发出了一个FIN和收到了一个ACK

正常情况下TCP连接的两端,是不同IP+端口的进程。

但如果TCP连接的两端,IP+端口是一样的情况下,那么在关闭连接的时候,也同样做到了一端发出了一个FIN,也收到了一个 ACK,只不过正好这两端其实是 。

TCP两次挥手

而这种两端IP+端口都一样的连接,叫TCP自连接

是的,你没看错,我也没打错别字。同一个socket确实可以自己连自己,形成一个连接。

一个socket能建立连接?

上面提到了,同一个客户端socket,自己对自己发起连接请求。是可以成功建立连接的。这样的连接,叫TCP自连接

下面我们尝试下复现。

注意我是在以下系统进行的实验。在上多半无法复现。

通过命令可以很简单的创建一个TCP自连接

上面的 可以指定源端口号。也就是指定了一个端口号为的客户端去连接 。

整个过程中,都没有服务端参与。可以抓个包看下。

image-20210810093309117

可以看到,相同的socket,自己连自己的时候,握手是三次的。挥手是两次的。

TCP自连接

上面这张图里,左右都是同一个客户端,把它画成两个是为了方便大家理解状态的迁移。

我们可以拿自连接的握手状态对比下正常情况下的TCP三次握手。

正常情况下的TCP三次握手

看了自连接的状态图,再看看下面几个问题。

一端发出第一次握手后,如果又收到了第一次握手的SYN包,TCP连接状态会怎么变化?

第一次握手过后,连接状态就变成了状态。如果此时又收到了第一次握手的SYN包,那么连接状态就会从状态变成。

一端发出第二次握手后,如果又收到第二次握手的SYN+ACK包,TCP连接状态会怎么变化?

第二握手过后,连接状态就变为了,此时如果再收到第二次握手的包。连接状态会变为。

一端第一次挥手后,又收到第一次挥手的包,TCP连接状态会怎么变化?

第一次挥手过后,一端状态就会变成 。正常情况下,是要等待第二次挥手的。但实际上却等来了 一个第一次挥手的 包, 这时候连接状态就会变为。

这可以说是隐藏剧情了。

很少见,除了出现在自连接关闭外,一般还会出现在TCP两端同时关闭连接的情况下。

处于状态下时,只要再收到一个,就能进入 状态,然后等个,连接就彻底断开了。这跟正常的四次挥手还是有些差别的。大家可以滑到文章开头的TCP四次挥手再对比下。

代码复现自连接

可能大家会产生怀疑,这是不是这个软件本身的。

那我们可以尝试下用看看它内部都做了啥。

无非就是以创建了一个客户端句柄,然后对这个句柄执行 , 绑定它的端口号是,然后再向 发起方法。

我们可以尝试用去复现一遍。

下面的代码,只用于复现问题。直接跳过也完全不影响阅读。

保存为 文件,然后执行下面命令,会发现连接成功。

说明,这不是nc的bug。事实上,这也是内核允许的一种情况。

自连接的解决方案

自连接一般不太常见,但遇到了也不难解决。

解决方案比较简单,只要能保证客户端和服务端的端口不一致就行。

事实上,我们写代码的时候一般不会去指定客户端的端口,系统会随机给客户端分配某个范围内的端口。而这个范围,可以通过下面的命令进行查询

也就是只要我们的服务器端口不在这个范围内,比如设置为。就可以规避掉这个问题。

另外一个解决方案,可以参考标准网络库的实现,在连接建立完成之后判断下IP和端口是否一致,如果遇到自连接,则断开重试。

四次握手

前面提到的自连接是一个客户端自己连自己的场景。那不同客户端之间是否可以互联?

答案是可以的,有一种情况叫TCP同时打开

TCP同时打开

大家可以对比下,TCP同时打开在握手时的状态变化,跟TCP自连接是非常的像。

比如状态下,又收到了一个,其实就相当于自连接里,在发出了第一次握手后,又收到了第一次握手的请求。结果都是变成 。

在 状态下收到了 ,就相当于自连接里,在发出第二次握手后,又收到第二次握手的请求,结果都是变成 。他们的源码其实都是同一块逻辑。

复现TCP同时打开

分别在两个控制台下,分别执行下面两行命令。

上面两个命令的含义也比较简单,两个客户端互相请求连接对方的端口号,如果失败了则不停重试。

执行后看到的现象是,一开始会疯狂失败,重试。一段时间后,连接建立完成。

期间抓包获得下面的结果。

可以看到,这里面建立连接用了四次交互。因此可以说这是通过"四次握手"建立的连接。

而且更重要的是,这里面只涉及两个客户端,没有服务端

看到这里,不知道大家有没有跟我一样,被刷新了一波认知,对有了重新的认识。

在以前的观念里,建立连接,必须要有一个客户端和一个服务端,并且服务端还要执行一个和一个。而实际上,这些都不是必须的。

那么下次,面试官问你"没有, TCP能建立连接吗?", 我想大家应该知道该怎么回答了。

但问题又来了,只有两个客户端,没有 ,为什么能建立连接?

如果大家感兴趣,我们以后有机会再填上这个坑。

总结

四次挥手中,不管是程序主动执行,还是进程被杀,都有可能发出第一次挥手包。如果机器上状态特别多,一般是因为对端一直不执行方法发出第三次挥手。

同时关闭发送和接收消息的功能。 能单独关闭发送或接受消息。

第二、第三次挥手,是有可能合在一起的。于是四次挥手就变成三次挥手了。

同一个socket自己连自己,会产生TCP自连接,自连接的挥手是两次挥手

没有,两个客户端之间也能建立连接。这种情况叫TCP同时打开,它由四次握手产生。

最后

今天提到的,不管是两次挥手,还是自连接,或是TCP同时打开什么的。

咋一看,可能对日常搬砖没什么用,实际上也确实没什么用。

并且在面试上大概率也不会被问到。

毕竟一般面试官也不在意茴字有几种写法。

这篇文章的目的,主要是想从另外一个角度让大家重新认识下。原来是可以自己连自己的,甚至两个客户端之间,不用服务端也能连起来。

这实在是,太出乎意料了。

如果文章对你有帮助,欢迎…..

算了。

兄弟们都是自家人,点不点赞,在不在看什么的,没关系的,大家看开心了就好。

在看,点赞什么的,我不是特别在意,真的,真的,别不信啊。

不三连也真的没关系的。

兄弟们不要在意啊。

我是虚伪的小白,我们下期见!

别说了,一起在知识的海洋里呛水吧

您可能还关注以下内容:

TCP三次握手和四次挥手是什么意思?

答:1、建立连接协议(三次握手) (1)客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。 (2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应;...

简述TCP三次握手四次挥手过程及各过程中客户端和服...

答:三次握手: 第一次握手:客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态; ...

简述tcp三次握手和四次挥手的过程.tcp和udp的区别...

答:1、建立连接协议(三次握手) (1)客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。 (2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应;...

TCP和UDP分别用于什么情况,tcp三次握手四次挥手?

答:tcp:提供面向连接的服务,数据传输前先建立连接,传输完毕后释放连接,提供可靠连接; udp:发送数据前不需要先建立连接,发送后也不需要释放连接,减少开销和延迟,但不保证可靠交付。 tcp建立连接的时候需要三次握手,释放连接需要4次挥手。

TCP为什么是三次握手,为什么不是两次或者四次

答:三次握手的目的:是为了确认双方都有收发数据的能力。 第一次: A->B,证明A有发消息的能力。 第二次: ->B && B->A,证明B有收消息,并且有发消息的能力。 第三次: A->B,证明A有收消息的能力。 二次握手达不到目的,四次多余。

三次握手及四次挥手在TCP/ip模型的哪一层进行的?...

答:在传输层进行的。 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器...

对TCP/IP三次握手及四次挥手的过程有点不太清楚,...

答:问题一:可以这么理解,SERVER的超时时间是可以调整的。 问题二:主要是为了多重复几次FIN,其实一般的用户程序做不了什么了。

TCP 为什么是三次握手,而不是两次或四次

答:两次太少,如果第一次握手时丢包了,那么如何判断网络是否通畅?因为两次丢包的意思是,对方确认并回复,如果没有收到回复,己方如何认为,他丢包了还是我丢包了?那就重传吧,如果并没有对方这个人,那么可能无限重传下去,浪费网络资源。三次...

谁能用通俗的话来 解释下 关于用 tcp/ip 协议 传输...

答:3次握手建立连接~ 就好象俩人说话~~ A对B说 兄弟 我给你发点东西你看看吧,(1次)~~B说好,那我接到了也给你回应(2次),~A说,行 就按你说的 咱开始传(3次) 4次握手释放连接~ A对B说 我传完了~~(1次)B说 我知道了。(2次)B对A说 我也传完...

为什么tcp连接的时候是三次握手,关闭的时候是四次...

答:TCP的三次握手和四次断开 TCP是一个面向连接的服务,面向连接的服务是电话系统服务模式的抽象,每一次完整的数据传输都必须经过建 立连接,数据传输和终止连接3个过程,TCP建立连接的过程称为三次握手,下面看一下三次握手的具本过程 TCP三次握手过程...

声明:以上内容并不代表本网赞同其观点。如有任何问题,请与不良与违法信息举报中心联系:513175919@qq.com。

www.book1234.com true http://www.book1234.com/q/20210825/20210825A0E51800.html report 44820
  • tcp三次握手四次挥手
  • 三次握手和四次挥手
  • tcp 握手挥手
  • tcp握手挥手练习题
  • tcp四次挥手
  • tcp四次挥手图解
  • tcp四次挥手状态转移
  • tcp关闭连接四次握手
  • tcp四次挥手图
  • tcp四次握手
  • 娱乐时尚
  • TCP三次握手和四次挥手是什么意思?
  • 简述TCP三次握手四次挥手过程及各过程中客户端和服...
  • 简述tcp三次握手和四次挥手的过程.tcp和udp的区别...
  • TCP和UDP分别用于什么情况,tcp三次握手四次挥手?
  • TCP为什么是三次握手,为什么不是两次或者四次
  • 三次握手及四次挥手在TCP/ip模型的哪一层进行的?...
  • 对TCP/IP三次握手及四次挥手的过程有点不太清楚,...
  • TCP 为什么是三次握手,而不是两次或四次
  • 谁能用通俗的话来 解释下 关于用 tcp/ip 协议 传输...
  • 为什么tcp连接的时候是三次握手,关闭的时候是四次...
  • 历史文化
    真视界
    旅游美食
    精彩图文
    我爱我车
    母婴健康
    关于本站 | 广告服务 | 手机版 | 商务合作 | 免责申明 | 招聘信息 | 联系我们
    Copyright © 2004-2018 book1234.com All Rights Reserved. 布客网 版权所有
    京ICP备2021021884号-4 京公网安备11010802011102号