浅谈3次握手与4次挥手

浅谈3次握手与4次挥手

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务端保存的一份关于对方的信息,如ip地址、端口号等。

一个TCP连接由一个4元组构成,分别是两个IP地址和两个端口号。一个TCP连接通常分为三个阶段:连接、数据传输、关闭。通过三次握手建立一个连接,通过四次挥手来关闭一个连接。当一个连接被建立或被终止时,交换的报文段只包含TCP头部,而没有数据。

TCP内部需要维护一个通信通道的全部相关信息,所以TCP内部抽象出一个对象(Connection)来进行连接管理。
在这里插入图片描述
如何判断接收到的数据Segment是否正确?
从TCP内部通过五元组获取连接对象 Connection,进而查看连接的状态信息Connection.state来确定是否正确。

0 TCP要经过三次握手建立连接, 四次挥手断开连接

需要三次握手,是因为双方进行通信需要先进行基本信息的同步。
当SYN标识位置1时,说明序列号SN用来同步信息的。当ACK置1时,说明确认序列号ASN是用确认信息的。

三次握手过程:
在这里插入图片描述
发送的Syn Segment 不会携带正式的通信数据,但是会消耗一个序列号。

三次握手四次挥手过程:
在这里插入图片描述

客户端状态转化:
[CLOSED -> SYN_SENT] 客户端调用connect, 发送同步报文段;
[SYN_SENT -> ESTABLISHED] 返回connect, 则进入ESTABLISHED状态, 开始读写数据;
[ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时, 向服务器发送结束报文段, 同时进入FIN_WAIT_1;
[FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段;
[FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出LAST_ACK;
[TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入CLOSED状态.

服务端状态转化:
[CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态, 等待客户端连接;
[LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认报文.

[SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入ESTABLISHED状态, 可以进行读写数据了.

[ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close), 服务器会收到结束报文段, 服务器返回确认报文段并进入CLOSE_WAIT;
[CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进入LAST_ACK状态, 等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)
[LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK, 彻底关闭连接.

状态变化:
状态变化
** TIME_WAIT:** 只出现在主动结束的一方

1 为什么TIME_WAIT的时间是2MSL?

(1)MSL是TCP报文的最大生存时间, 因此TIME_WAIT持续存在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失,让这个连接不会跟后面的连接混在一起(否则服务器立刻重启, 可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的);
(2)保证最后一个报文可靠到达 (假设最后一个ACK丢失, 那么服务器会再重发一个FIN,一来一去正好2个MSl,这时虽然客户端的进程不在了, 但是TCP连接还在, 仍然可以重发LAST_ACK);

2 CLOSE_WAIT:只出现在被动结束的一方

一般而言,对于服务器上出现大量的CLOSE_WAIT 状态, 原因就是服务器没有正确的关闭socket, 导致四次挥手没有正确完成. 这是一个BUG. 只需要加上对应的close 即可解决问题

3 为什么TCP建立连接是三次握手,不是两次也不是四次?

同步信息的过程两端都需要进行确认ISN(Inital Sequence Number,初始序列编号),以确认两端都具有收发信息的能力,三次握手能够保证TCP连接的需求,因为被动方发送ACK和SYN是可以合并的,完全没必要进行四次握手,而两次肯定是不满足信息同步要求的。

注:
初始序列编号ISN要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序(TCP会用这个序号来拼接数据)。

参考:
https://cloud.tencent.com/developer/article/1417777

注意:
ISN的初始化时,ISN是不能硬编码的。比如:如果连接建好后始终用1来做ISN,如果client发了30个segment过去,但是网络断了,于是 client重连,又用了1做ISN,但是之前连接的那些包到了,于是就被当成了新连接的包,此时,client的Sequence Number 可能是3,而Server端认为client端的这个号是30了,全乱了。

4 为什么连接的时候是三次握手,关闭的时候却是四次握手?

因为当被动方收到主动方的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。

但是关闭连接时,当被动方收到FIN报文时,很可能并不会立即关闭SOCKET,因为被动方需要等待应用层处理完毕,所以只能先回复一个ACK报文, 告诉Client端,“你发的FIN报文我收到了”。只有等到被动方所有的报文都发送完了,我才能发送FIN报文, 因此不能一起发送。且socket套接字是全双工的,一个收一个发,一共两个通道,需要连接两端分别发送FIN且接收到ACK,所以才产生了四次挥手。

注意:
客户端可以先close是因为,客户端不绑定固定端口,再次调用时,系统会重新分配端口,而如果服务器先调close,最后资源保留2-5分钟,再次运行时,将会报错(Address already in use),因为服务器绑定固定端口,此时的资源未被释放(端口仍被占用)。

5 TCP异常情况

(1)进程终止: 进程终止会释放文件描述符, 仍然可以发送FIN. 和正常关闭没有什么区别.

(2)机器重启: 和进程终止的情况相同.

(3)机器掉电/网线断开:

1) 对关机方A来说,内存的数据全部失效,连接也不会存在了。而B端收不到A端的通知了,如果B端准备发送(write)数据,那么一定会触发超时重传,当重传到一定次数时,则抛出异常来通知连接出问题了,连接对象会被直接释放掉,此时B端也会尝试发送一个RST给A端,如果A能收到,则A能够知道B已经关闭连接了,收不到也无所谓了。如果B端正准备读数据(read),那么B端无法区分是A端没有发送数据还是A端已经断电了。针对这个问题,即使B端正在读数据,也会定期发送一个不携带数据的Segment给A,检验A有没有应答(TCP中的keepalive机制)。应用层的某些协议, 也有一些这样的检测机制. 例如HTTP长连接中, 也会定期检测对方的状态. 例如QQ, 在QQ断线之后, 也会定期尝试重新连接。

注意:
keepalive机制很少使用,定期发送segment的配置是针对这台设备的所有TCP连接的,且定期时间比较长(默认2个小时)。在应用层进行处理,这样就可以对每个连接进行独立管理。比如在TCP连接中可以设置读read的超时时间,如果超时了还未读到数据,就会主动给对方发送一段数据(heartbeat 心跳包),来确认对方的状态。

2) 断电的A端重新启动了
如果B是read状态,就会和上面一致。
如果B是write状态,则B的TCP Segment会传给A,而由于A端的连接已经不存在了,所以当A的TCP协议栈根据五元组信息是查不到连接的。那么A端会传一个RST Segment,B收到后,就会正常关闭B端的连接(通过异常通知应用层,释放内存的连接数据)。B端的应用层收到异常通知后,会尝试建立新的连接进行通信。

注意:
标识位:RST(Reset):用于连接异常

  1. 需要发送RST的情况:
    (1)根据五元组无法找到一个连接时
    (2)找到连接了,但是状态不正常时
    (3)序列号不在合法的范围内
    发送RST,同时也伴随着自己的TCP连接关闭(异常)(异常通知应用层,释放连接内存)

  2. 接收到RST时:
    TCP连接关闭(异常)(异常通知应用层,释放连接内存)

Syn Flood Attack(Syn 洪水攻击): 操控一大波电脑(肉鸡),向固定连接S只发送一次SYN。S为了维护这些连接(连接状态停留在SYN_RCVD)需要占用大量内存,导致S设备中的其他进程就无法正常工作了。

参考博客:
[1] https://www.cnblogs.com/missmzt/p/5308149.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值