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

32768~61000 , 也可以通过如下参数设置指定
net.ipv4.ip_local_port_range
如果服务端 TIME_WAIT 状态过多 , 占满了所有端口资源 , 则会导致无法创建新连接 。
如何优化 TIME_WAIT?
这里给出优化 TIME-WAIT 的几个方式 , 都是有利有弊:

  • 打开 net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 选项;
  • net.ipv4.tcp_max_tw_buckets
  • 程序中使用 SO_LINGER, 应用强制使用 RST 关闭 。
方式一:net.ipv4.tcp_tw_reuse 和 tcp_timestamps
如下的 Linux 内核参数开启后 , 则可以复用处于 TIME_WAIT 的 socket 为新的连接所用 。
net.ipv4.tcp_tw_reuse = 1
使用这个选项 , 还有一个前提 , 需要打开对 TCP 时间戳的支持 , 即
net.ipv4.tcp_timestamps=1(默认即为 1)
这个时间戳的字段是在 TCP 头部的「选项」里 , 用于记录 TCP 发送方的当前时间戳和从对端接收到的最新时间戳 。
由于引入了时间戳 , 我们在前面提到的 2MSL 问题就不复存在了 , 因为重复的数据包会因为时间戳过期被自然丢弃 。
温馨提醒:net.ipv4.tcp_tw_reuse要慎用 , 因为使用了它就必然要打开时间戳的支持 net.ipv4.tcp_timestamps , 当客户端与服务端主机时间不同步时 , 客户端的发送的消息会被直接拒绝掉 。 小林在工作中就遇到过 。。。 排查了非常的久
方式二:net.ipv4.tcp_max_tw_buckets
这个值默认为 18000 , 当系统中处于 TIME_WAIT 的连接一旦超过这个值时 , 系统就会将所有的 TIME_WAIT 连接状态重置 。
这个方法过于暴力 , 而且治标不治本 , 带来的问题远比解决的问题多 , 不推荐使用 。
方式三:程序中使用 SO_LINGER
我们可以通过设置 socket 选项 , 来设置调用 close 关闭连接行为 。
struct linger so_linger;
so_linger.l_onoff = 1;so_linger.l_linger = 0;setsockopt(s SOL_SOCKET SO_LINGER &so_lingersizeof(so_linger));
如果l_onoff为非 0 ,且l_linger值为 0 , 那么调用close后 , 会立该发送一个RST标志给对端 , 该 TCP 连接将跳过四次挥手 , 也就跳过了TIME_WAIT状态 , 直接关闭 。
但这为跨越TIME_WAIT状态提供了一个可能 , 不过是一个非常危险的行为 , 不值得提倡 。
如果已经建立了连接 , 但是客户端突然出现故障了怎么办?
TCP 有一个机制是保活机制 。 这个机制的原理是这样的:
定义一个时间段 , 在这个时间段内 , 如果没有任何连接相关的活动 , TCP 保活机制会开始作用 , 每隔一个时间间隔 , 发送一个探测报文 , 该探测报文包含的数据非常少 , 如果连续几个探测报文都没有得到响应 , 则认为当前的 TCP 连接已经死亡 , 系统内核将错误信息通知给上层应用程序 。
在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔 , 以下都为默认值:
net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75net.ipv4.tcp_keepalive_probes=9