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

如果l_onoff为非 0 ,且l_linger值为 0 , 那么调用close后 , 会立该发送一个RST标志给对端 , 该 TCP 连接将跳过四次挥手 , 也就跳过了TIME_WAIT状态 , 直接关闭 。
但这为跨越TIME_WAIT状态提供了一个可能 , 不过是一个非常危险的行为 , 不值得提倡 。
如果已经建立了连接 , 但是客户端突然出现故障了怎么办?
TCP 有一个机制是保活机制 。 这个机制的原理是这样的:
定义一个时间段 , 在这个时间段内 , 如果没有任何连接相关的活动 , TCP 保活机制会开始作用 , 每隔一个时间间隔 , 发送一个探测报文 , 该探测报文包含的数据非常少 , 如果连续几个探测报文都没有得到响应 , 则认为当前的 TCP 连接已经死亡 , 系统内核将错误信息通知给上层应用程序 。
在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔 , 以下都为默认值:
net.ipv4.tcp_keepalive_time=7200net.ipv4.tcp_keepalive_intvl=75net.ipv4.tcp_keepalive_probes=9

  • tcp_keepalive_time=7200:表示保活时间是 7200 秒(2小时) , 也就 2 小时内如果没有任何连接相关的活动 , 则会启动保活机制
  • tcp_keepalive_intvl=75:表示每次检测间隔 75 秒;
  • tcp_keepalive_probes=9:表示检测 9 次无响应 , 认为对方是不可达的 , 从而中断本次的连接 。
也就是说在 Linux 系统中 , 最少需要经过 2 小时 11 分 15 秒才可以发现一个「死亡」连接 。
Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
本文插图
这个时间是有点长的 , 我们也可以根据实际的需求 , 对以上的保活相关的参数进行设置 。
如果开启了 TCP 保活 , 需要考虑以下几种情况:
第一种 , 对端程序是正常工作的 。 当 TCP 保活的探测报文发送给对端, 对端会正常响应 , 这样 TCP 保活时间会被重置 , 等待下一个 TCP 保活时间的到来 。
第二种 , 对端程序崩溃并重启 。 当 TCP 保活的探测报文发送给对端后 , 对端是可以响应的 , 但由于没有该连接的有效信息 , 会产生一个 RST 报文 , 这样很快就会发现 TCP 连接已经被重置 。
第三种 , 是对端程序崩溃 , 或对端由于其他原因导致报文不可达 。 当 TCP 保活的探测报文发送给对端后 , 石沉大海 , 没有响应 , 连续几次 , 达到保活探测次数后 , TCP 会报告该 TCP 连接已经死亡 。
Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
本文插图
Socket 编程针对 TCP 应该如何 Socket 编程?
Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
本文插图
基于 TCP 协议的客户端和服务器工作
  • 服务端和客户端初始化 socket , 得到文件描述符;
  • 服务端调用 bind , 将绑定在 IP 地址和端口;
  • 服务端调用 listen , 进行监听;
  • 服务端调用 accept , 等待客户端连接;
  • 客户端调用 connect , 向服务器端的地址和端口发起连接请求;
  • 服务端 accept 返回用于传输的 socket 的文件描述符;
  • 客户端调用 write 写入数据;服务端调用 read 读取数据;
  • 客户端断开连接时 , 会调用 close , 那么服务端 read 读取数据的时候 , 就会读取到了 EOF , 待处理完数据后 , 服务端调用 close , 表示连接关闭 。
这里需要注意的是 , 服务端调用 accept 时 , 连接成功了会返回一个已完成连接的 socket , 后续用来传输数据 。


推荐阅读