Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题(11)


所以 , 监听的 socket 和真正用来传送数据的 socket , 是「两个」 socket , 一个叫作监听 socket , 一个叫作已完成连接 socket 。
成功连接建立之后 , 双方开始通过 read 和 write 函数来读写数据 , 就像往一个文件流里面写东西一样 。
listen 时候参数 backlog 的意义?
Linux内核中会维护两个队列:

  • 未完成连接队列(SYN 队列):接收到一个 SYN 建立连接请求 , 处于 SYN_RCVD 状态;
  • 已完成连接队列(Accpet 队列):已完成 TCP 三次握手过程 , 处于 ESTABLISHED 状态;

Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
本文插图
SYN 队列 与 Accpet 队列
int listen (int socketfd, int backlog)
  • 参数一 socketfd 为 socketfd 文件描述符
  • 参数二 backlog , 这参数在历史有一定的变化
在早期 Linux 内核 backlog 是 SYN 队列大小 , 也就是未完成的队列大小 。
在 Linux 内核 2.2 之后 , backlog 变成 accept 队列 , 也就是已完成连接建立的队列长度 , 所以现在通常认为 backlog 是 accept 队列 。
accept 发送在三次握手的哪一步?
我们先看看客户端连接服务端时 , 发送了什么?
Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
本文插图
客户端连接服务端
  • 客户端的协议栈向服务器端发送了 SYN 包 , 并告诉服务器端当前发送序列号 client_isn , 客户端进入 SYNC_SENT 状态;
  • 服务器端的协议栈收到这个包之后 , 和客户端进行 ACK 应答 , 应答的值为 client_isn+1 , 表示对 SYN 包 client_isn 的确认 , 同时服务器也发送一个 SYN 包 , 告诉客户端当前我的发送序列号为 server_isn , 服务器端进入 SYNC_RCVD 状态;
  • 客户端协议栈收到 ACK 之后 , 使得应用程序从 connect 调用返回 , 表示客户端到服务器端的单向连接建立成功 , 客户端的状态为 ESTABLISHED , 同时客户端协议栈也会对服务器端的 SYN 包进行应答 , 应答数据为 server_isn+1;
  • 应答包到达服务器端后 , 服务器端协议栈使得 accept 阻塞调用返回 , 这个时候服务器端到客户端的单向连接也建立成功 , 服务器端也进入 ESTABLISHED 状态 。
从上面的描述过程 , 我们可以得知客户端 connect 成功返回是在第二次握手 , 服务端 accept 成功返回是在三次握手成功之后 。
客户端调用 close 了 , 连接是断开的流程是什么?
我们看看客户端主动调用了 close , 会发生什么?
Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
本文插图
客户端调用 close 过程