「客户端」学习网络编程,不了解TCP协议?难怪面试被刷下去,还不来学习!(11)


也就是说在 Linux 系统中 , 最少需要经过 2 小时 11 分 15 秒才可以发现一个「死亡」连接 。
这个时间是有点长的 , 我们也可以根据实际的需求 , 对以上的保活相关的参数进行设置 。
如果开启了 TCP 保活 , 需要考虑以下几种情况:
第一种 , 对端程序是正常工作的 。 当 TCP 保活的探测报文发送给对端 对端会正常响应 , 这样 TCP 保活时间会被重置 , 等待下一个 TCP 保活时间的到来 。
第二种 , 对端程序崩溃并重启 。 当 TCP 保活的探测报文发送给对端后 , 对端是可以响应的 , 但由于没有该连接的有效信息 , 会产生一个 RST 报文 , 这样很快就会发现 TCP 连接已经被重置 。
第三种 , 是对端程序崩溃 , 或对端由于其他原因导致报文不可达 。 当 TCP 保活的探测报文发送给对端后 , 石沉大海 , 没有响应 , 连续几次 , 达到保活探测次数后 , TCP 会报告该 TCP 连接已经死亡 。
03 Socket 编程针对 TCP 应该如何 Socket 编程?

基于 TCP 协议的客户端和服务器工作

  • 服务端和客户端初始化 socket , 得到文件描述符;
  • 服务端调用 bind , 将绑定在 IP 地址和端口;
  • 服务端调用 listen , 进行监听;
  • 服务端调用 accept , 等待客户端连接;
  • 客户端调用 connect , 向服务器端的地址和端口发起连接请求;
  • 服务端 accept 返回用于传输的 socket 的文件描述符;
  • 客户端调用 write 写入数据;服务端调用 read 读取数据;
  • 客户端断开连接时 , 会调用 close , 那么服务端 read 读取数据的时候 , 就会读取到了 EOF , 待处理完数据后 , 服务端调用 close , 表示连接关闭 。
这里需要注意的是 , 服务端调用 accept 时 , 连接成功了会返回一个已完成连接的 socket , 后续用来传输数据 。
所以 , 监听的 socket 和真正用来传送数据的 socket , 是「两个」 socket , 一个叫作监听 socket , 一个叫作已完成连接 socket 。
成功连接建立之后 , 双方开始通过 read 和 write 函数来读写数据 , 就像往一个文件流里面写东西一样 。
listen 时候参数 backlog 的意义?
Linux内核中会维护两个队列:
  • 未完成连接队列(SYN 队列):接收到一个 SYN 建立连接请求 , 处于 SYN_RCVD 状态;
  • 已完成连接队列(Accpet 队列):已完成 TCP 三次握手过程 , 处于 ESTABLISHED 状态;

SYN 队列 与 Accpet 队列

int listen (int socketfd int backlog)
  • 参数一 socketfd 为 socketfd 文件描述符
  • 参数二 backlog , 这参数在历史有一定的变化
在早期 Linux 内核 backlog 是 SYN 队列大小 , 也就是未完成的队列大小 。
在 Linux 内核 2.2 之后 , backlog 变成 accept 队列 , 也就是已完成连接建立的队列长度 , 所以现在通常认为 backlog 是 accept 队列 。
accept 发送在三次握手的哪一步?
我们先看看客户端连接服务端时 , 发送了什么?
客户端连接服务端