52-提高篇答疑:如何理解TCP四次挥手?

1、提高篇答疑:如何理解TCP四次挥手?

1.1、如何理解 TCP 四次挥手?

TCP 建立一个连接需 3 次握手,而终止一个连接则需要四次挥手。四次挥手的整个过程是这样的:
在这里插入图片描述

首先,一方应用程序调用 close,我们称该方为主动关闭方,该端的 TCP 发送一个 FIN 包,表示需要关闭连接。

之后主动关闭方进入 FIN_WAIT_1 状态。

接着,接收到这个 FIN 包的对端执行被动关闭。

这个 FIN 由 TCP 协议栈处理,我们知道,TCP 协议栈为 FIN 包插入一个文件结束符 EOF 到接收缓冲区中,应用程序可以通过 read 调用来感知这个 FIN 包。

一定要注意,这个 EOF 会被放在已排队等候的其他已接收的数据之后,这就意味着接收端应用程序需要处理这种异常情况,因为 EOF 表示在该连接上再无额外数据到达。此时,被动关闭方进入 CLOSE_WAIT 状态。

接下来,被动关闭方将读到这个 EOF,于是,应用程序也调用 close 关闭它的套接字,这导致它的 TCP 也发送一个 FIN 包。

这样,被动关闭方将进入 LAST_ACK 状态。

最终,主动关闭方接收到对方的 FIN 包,并确认这个 FIN 包。

主动关闭方进入 TIME_WAIT 状态,而接收到 ACK 的被动关闭方则进入 CLOSED 状态。

经过 2MSL 时间之后,主动关闭方也进入 CLOSED 状态。

每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。

当然,这中间使用 shutdown,执行一端到另一端的半关闭也是可以的。

1.2、最大分组 MSL 是 TCP 分组在网络中存活的最长时间吗?

MSL 是任何 IP 数据报能够在因特网中存活的最长时间。

其实它的实现不是靠计时器来完成的,在每个数据报里都包含有一个被称为 TTL(time to live)的 8 位字段,它的最大值为 255。

TTL 可译为“生存时间”,这个生存时间由源主机设置初始值,它表示的是一个 IP 数据报可以经过的最大跳跃数,每经过一个路由器,就相当于经过了一跳,它的值就减 1,当此值减为 0 时,则所在的路由器会将其丢弃,同时发送 ICMP 报文通知源主机。

RFC793 中规定 MSL 的时间为 2 分钟,Linux 实际设置为 30 秒。

问题:MSL和TTL的关系?

TTL:

  • Time To Live 指定了IP包允许跳转(允许通过的最大网段数量)的路由器数量,最大值为255,推荐值为64;
  • TTL在IP数据包中表示。

IP数据包每经过一个路由器其值就会-1,一旦TTL=0路由器就会将该IP数据包丢弃,并向IP包的发送者发送 ICMP time exceeded消息;

TTL主要就是为了防止IP数据包在网络上出现无限的循环跳转,一旦出现循环跳转的话就会比较浪费网络资源

MSL:

Maximum Segment Lifetime最大报文段生存时间,MSL要大于等于TTL

  • 一旦IP包只要送到对方的机器上,那么此包就一定不会超过MSL
  • 如果MSL小于TTL那么IP包送到了但是TCP包超时了那么就会比较浪费资源,并且因为TCP包是包含在IP包上的,里面的时间按逻辑上就应该大于等于TTL的
  • 所以只要经过了MSL时间,那么TCP包就肯定已经被传输线路上的路由器给丢弃了

1.3、关于 listen 函数中参数 backlog 的释义问题

从 Linux 2.2 开始,backlog 的参数内核有了新的语义,它现在定义的是已完成连接队列的最大长度,表示的是已建立的连接(established connection),正在等待被接收(accept 调用返回)

listen 函数:

int listen (int socketfd, int backlog)

第一个参数 socketdf 为套接字描述符;

第二个参数 backlog,在 Linux 中表示已完成 (ESTABLISHED) 且未 accept 的队列大小,这个参数的大小决定了可以接收的并发数目。这个参数越大,并发数目理论上也会越大。但是参数过大也会占用过多的系统资源,一些系统,比如 Linux 并不允许对这个参数进行改变。

1.4、UDP 连接和断开套接字的过程是怎样的?

UDP 连接套接字不是发起连接请求的过程,而是记录目的地址和端口到套接字的映射关系

断开套接字则相反,将删除原来记录的映射关系

UDP调用connect,只是将目的地址和端口到socket的映射关系记录了下来,这样内核收到ICMP报文后就能转发给对应的UDP应用

1.5、在 UDP 中不进行 connect,为什么客户端会收到信息?

问题:

​ 有人说,如果按照我在文章中的说法,UDP 只有 connect 才建立 socket 和 IP 地址的映射,那么如果不进行 connect,收到信息后内核又如何把数据交给对应的 socket?

这是两个不同的 API 场景。

**第一个场景:**就是讨论的 connect 场景,在这个场景里,我们讨论的是 ICMP 报文和 socket 之间的定位

  • 我们知道,ICMP 报文发送的是一个不可达的信息,不可达的信息是通过目的地址和端口来区分的,如果没有 connect 操作,目的地址和端口就没有办法和 socket 套接字进行对应,所以,即使收到了 ICMP 报文,内核也没有办法通知到对应的应用程序,告诉它连接地址不可达。

为什么在不 connect 的情况下,我们的客户端又可以收到服务器回显的信息了?

**第二个场景:**报文发送的场景

  • 注意服务器端程序,先通过 recvfrom 函数调用获取了客户端的地址和端口信息,这当然是可以的,因为 UDP 报文里面包含了这部分信息。
  • 然后我们看到服务器端又通过调用 sendto 函数,把客户端的地址和端口信息告诉了内核协议栈,可以肯定的是,之后发送的 UDP 报文就带上了客户端的地址和端口信息,通过客户端的地址和端口信息,可以找到对应的套接字和应用程序,完成数据的收发。
//服务器端程序,先通过recvfrom函数调用获取了客户端的地址和端口信息
int n = recvfrom(socket_fd, message, MAXLINE, 0, (struct sockaddr *) &client_addr, &client_len);
message[n] = 0;
printf("received %d bytes: %s\n", n, message);

char send_line[MAXLINE];
sprintf(send_line, "Hi, %s", message);

//服务器端程序调用send函数,把客户端的地址和端口信息告诉了内核
sendto(socket_fd, send_line, strlen(send_line), 0, (struct sockaddr *) &client_addr, client_len);

总结:

从代码中可以看到:

  • 这里的 connect 的作用是记录客户端目的地址和端口–套接字的关系
  • 而之所以能正确收到从服务器端发送的报文,那是因为系统已经记录了客户端源地址和端口–套接字的映射关系。

1.6、我们是否可以对一个 UDP 套接字进行多次 connect 的操作?

  • TCP 套接字,connect 只能调用一次。
  • UDP 套接字来说,进行多次 connect 操作是被允许的

UDP套接字多次connect的作用:

  • 可以重新指定新的 IP 地址和端口号;
  • 可以断开一个已连接的套接字;为了断开一个已连接的 UDP 套接字,第二次调用 connect 时,调用方需要把套接字地址结构的地址族成员设置为 AF_UNSPEC。

1.7、第 11 讲中程序和时序图的解惑

在 11 讲中,我们讲了关闭连接的几种方式,有同学对这一篇文章中的程序和时序图存在疑惑,并提出了下面几个问题:

问题:

1、当一方主动 close 之后,另一方发送数据的时候收到 RST。主动方缓冲区会把这个数据丢弃吗?这样的话,应用层应该读不到了吧?

2、代码中 SIGPIPE 的作用不是忽略吗?为什么服务器端会退出?

默认的 SIGPIPE 忽略行为就是退出程序,什么也不做,当然,实际程序还是要做一些清理工作的。

3、shutdown关闭一段的情况;

  • 如果主动关闭的一方调用 shutdown 关闭写端,没有关闭读这一端,主动关闭的一方可以读到对端的数据;
  • 注意这个时候主动关闭连接的一方是在使用 read 方法进行读操作,而不是 write 写操作,不会有 RST 的发生,更不会有 SIGPIPE 的发生。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liufeng2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值