三次握手与四次挥手

三次握手与四次挥手

1.什么是可靠性?

1.具有应答,可以保证对历史数据的可靠性

2.通信中,最新的报文永远没有应答,最新可靠性无法保证

如果要保证可靠性,需要在tcp中把确认应答机制放在核心位置


总结:

TCP保证可靠性的核心是确认应答机制,可靠性的本质是对历史消息的确认应答

客户端给服务器发消息,服务器就必须要应答,这个应答是由对方操作系统发的

通常是并行发的,串行发消息效率太低了

TCP传递报文传递的是带有TCP报头的报文,应答是指只带有TCP报头

流量控制

一台主机接收数据的大小由接收缓冲区剩余大小空间来做决定

我们所构建的报文都是给对方的

流量控制是为了合理地控制流量,就好像每个人接收能力有差异需要动态调整

TCP 头部结构的定义:

C++ 复制代码
struct tcphdr {
    __be16  source;     /* 源端口号 */
    __be16  dest;       /* 目的端口号 */
    __be32  seq;        /* 序列号 */
    __be32  ack_seq;    /* 确认号 */
#if defined(__LITTLE_ENDIAN_BITFIELD)
    __u16   res1:4,     /* 保留位 */
            doff:4,     /* 数据偏移(头部长度) */
            fin:1,      /* FIN 标志 */
            syn:1,      /* SYN 标志 */
            rst:1,      /* RST 标志 */
            psh:1,      /* PSH 标志 */
            ack:1,      /* ACK 标志 */
            urg:1,      /* URG 标志 */
            ece:1,      /* ECN-Echo 标志 */
            cwr:1;      /* 拥塞窗口减少标志 */
#elif defined(__BIG_ENDIAN_BITFIELD)
    __u16   doff:4,     /* 数据偏移(头部长度) */
            res1:4,     /* 保留位 */
            cwr:1,      /* 拥塞窗口减少标志 */
            ece:1,      /* ECN-Echo 标志 */
            urg:1,      /* URG 标志 */
            ack:1,      /* ACK 标志 */
            psh:1,      /* PSH 标志 */
            rst:1,      /* RST 标志 */
            syn:1,      /* SYN 标志 */
            fin:1;      /* FIN 标志 */
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
    __be16  window;     /* 窗口大小 */
    __sum16 check;      /* 校验和 */
    __be16  urg_ptr;    /* 紧急指针 */
};

标志位本质是报头的比特位

为什么需要标志位?

TCP接收方会有不同类型的报文,针对不同类型,需要有不同的做法,要有表示报文类型的字段,需要标志位

每一个 ACK 都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发由你自己决定.

那么, 如果超时的时间如何确定?

• 最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回".

• 但是这个时间的长短, 随着网络环境的不同, 是有差异的.

• 如果超时时间设的太长, 会影响整体的重传效率;

• 如果超时时间设的太短, 有可能会频繁发送重复的包;

TCP 为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间.

• Linux 中(BSD Unix 和 Windows 也是如此), 超时以 500ms 为一个单位进行控制, 每次判定超时重发的超时时间都是 500ms 的整数倍.

• 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.

• 如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.

• 累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接.

相关习题:

1.主机甲向主机乙发送一个(SYN=1,seq=11220)的TCP段,期望与主机乙建立TCP连接,若主机乙接受该连接请求,则主机乙向主机甲发送的正确的TCP段应该是()

A.(SYN=1,ACK=1,seq=11220,ack=11220)

B.(SYN=1,ACK=1,seq=11221,ack=11221)

C.(SYN=0,ACK=0,seq=11221,ack=11221)

D.(SYN=0,ACK=1,seq=11220,ack=11220)

SYN和ACK是TCP协议报头中的6个保留位中的2位。

ACK:ACK位置为1表明确认号是合法的。如果ACK为0,那么数据报不包含确认信息,确认字段被省略。

seq:发送方的本条报文起始序号

ack:对于上次对方发送的数据的确认序号,通常是对方发送的数据的起始序号+数据长度,但是在三次握手阶段稍有不同,是上次对方发送的请求的起始序号+1

SYN=1,seq=11220, SYN=1表示这是一个客户端的第一次握手连接建立请求, 并且起始序号为11220

服务器收到请求后,向客户端进行第二次握手,第二次握手既是自己的连接建立请求,也是对客户端连接请求的确认,因此 SYN=1,ACK=1, 而确认序号为对方的起始序号+1, 则为11221

则 SYN=1,ACK=1,ack=11221,seq=自己的起始序号,一般为随机值这个不做要求

则符合条件的只有B选项

2.下列哪项最恰当地描述了建立TCP连接时"第一次握手"所做的工作 ( )

A."连接发起方"向"接收方"发送一个SYN-ACK段

B."接收方"向"连接发起方"发送一个SYN-ACK段

C."连接发起方"向目标主机的TCP进程发送一个SYN段

D."接收方"向源主机得到TCP进程发送一个SYN段作为应答

TCP三次握手过程:

  • 第一次握手:客户端向服务器发送连接请求, 也就是SYN段
  • 第二次握手:服务器向客户端发送确认回复及连接请求, 也就是 SYN+ACK段
  • 第三次握手:客户端向服务器发送确认回复,也就是ACK段

基于以上理解,正确选项为:C

【多选题】客户端主动断开TCP连接的时候,以下"四次挥手"过程中状态变迁表述正确的是()

A.Client发送一个FIN,用来关闭Client到Server之间的数据传输,Client进入FIN_WAIT1状态

B.Server收到了来自Client的FIN包,发送一个ack给client,进入CLOSE_WAIT状态

C.Server发送一个FIN,用来关闭Server到Client之间的数据传输,Server进入LAST_ACK状态

D.Client收到FIN包之后,Client发送一个ACK给Server, 紧接着进入TIME_WAIT状态,Server收到ack后进入CLOSED状态

【多选题】客户端主动断开TCP连接的时候,以下"四次挥手"过程中表述错误的是()

A.当Client收到Server的ACK包之后,Client状态变成FIN_WAIT2状态

B.当Server发送FIN包到Client之后,Client需要等待1MSL,状态才从TIME_WAIT状态变成CLOSED状态

C.Server端出现大量的CLOSE_WAIT状态,是由于Client没有及时的关闭连接

D."四次挥手"是完全没有必要的,"三次挥手"就可以了

A正确

B错误:当Server发送FIN包到Client之后,Client需要等待2MSL,处理有可能因为最后一次ACK丢失导致的重传(重传的FIN是1MSL,自己发送的ACK是1MSL,共2MSL),最终状态才从TIME_WAIT状态变成CLOSED状态

C错误:CLOSE_WAIT状态是被动关闭方收到FIN并进行ACK回复后进入的状态,接下来他会等待上层知道对方要关闭连接后做出处理,当自己也要关闭连接的时候给对方发送FIN,则 进入LAST_ACK状态,而一旦自己上层没有做出处理,则套接字状态会一直处于CLOSE_WAIT, 因此Server端出现大量的CLOSE_WAIT,是由于Server端没有及时的关闭连接导致的。

D错误:这里需要了解FIN的功能,收到FIN只能表示对方不再给自己发送数据,而不是完全关闭既不发送数据也不再接收数据,他还是可以继续接收数据的,因此被动关闭方收到FIN请求进行ACK确认后,可能还会继续发送数据,直到自己也不再发送了,才会发送接下来的FIN包,因此四次挥手不能合并成为 三次挥手。

总结:

1. 三次握手:建立可靠的双向通道

  • 第一次握手(Client -> Server) :发送SYN=1, seq=J。Client说:"我要建立连接,我的初始序列号是J。"
  • 第二次握手(Server -> Client) :发送SYN=1, ACK=1, seq=K, ack=J+1。Server说:"我同意连接(ACK),我的初始序列号是K。同时,你发的J我收到了,下次请你从J+1开始发。"
  • 第三次握手(Client -> Server) :发送ACK=1, ack=K+1。Client说:"好的,你发的K我也收到了,下次从K+1开始。"

为什么是三次?

两次握手只能保证Client知道Server的收发能力正常,但Server无法确认Client的接收能力是否正常。第三次握手就是为了让Server确认这一点,从而建立起一个可靠的双向通信通道

2. 四次挥手:优雅地关闭双向通道

TCP连接是全双工的,意味着双方可以独立地发送和接收数据。因此,关闭连接也需要双方各自关闭。

  • 第一次挥手(Client -> Server)FIN=1。Client说:"我数据发完了,要关闭我这边到你的发送通道了。"(Client进入FIN_WAIT_1
  • 第二次挥手(Server -> Client)ACK=1。Server说:"哦了,知道你关发送通道了。"(Server进入CLOSE_WAIT,Client进入FIN_WAIT_2注意:此时Server可能还有数据要发给Client,所以它的发送通道还开着。
  • 第三次挥手(Server -> Client)FIN=1。Server也发完了所有数据,说:"我也发完了,我也要关闭我这边到你的发送通道了。"(Server进入LAST_ACK
  • 第四次挥手(Client -> Server)ACK=1。Client说:"收到,再见!"(Client进入TIME_WAIT,等待2MSL后关闭;Server收到ACK后直接关闭)

为什么是四次?

第三次挥手(Server -> Client)FIN=1。Server也发完了所有数据,说:"我也发完了,我也要关闭我这边到你的发送通道了。"(Server进入LAST_ACK

  • 第四次挥手(Client -> Server)ACK=1。Client说:"收到,再见!"(Client进入TIME_WAIT,等待2MSL后关闭;Server收到ACK后直接关闭)

为什么是四次?

因为中间可能有一个"等待数据处理并发送完毕"的间隔期(CLOSE_WAIT状态)。这无法与第二次挥手的ACK合并 ,所以需要四次。

相关推荐
一勺-_-4 天前
网络层五层协议
tcp
小许学java5 天前
网络编程套接字
java·网络·udp·socket·tcp·套接字
阿巴~阿巴~9 天前
JsonCpp:C++ JSON处理利器
linux·网络·c++·json·tcp·序列化和反序列化
cccyi79 天前
传输层协议:UDP 与 TCP 原理详解
计算机网络·udp·tcp
daidaidaiyu12 天前
Jetlinks 物联网平台 开源版学习源码分析
java·mqtt·rxjava·tcp
LaoZhangGong12314 天前
以太网HTTP数据包格式分析
c语言·stm32·网络协议·http·tcp·arp
罗汉松(山水白河)14 天前
关于串口与UDP通讯的实验
单片机·嵌入式硬件·网络协议·udp·tcp·串口、
阿巴~阿巴~16 天前
TCP服务器实现全流程解析(简易回声服务端):从套接字创建到请求处理
linux·服务器·网络·c++·tcp·socket网络编程
_星辰大海乀17 天前
TCP 协议
网络·网络协议·tcp/ip·tcp