公网服务器或客户端为 NAT 网络的服务器不要同时开启 tcp_tw_recycle 和 tcp_timestamps
来源:互联网 发布:淘宝如何绑定银行卡 编辑:程序博客网 时间:2024/06/02 14:39
目录
- 目录
- 背景及现象
- 问题原因
- 结论
- 实践
- 如何配置 tcp_tw_recycle 和 tcp_timestamps
- 为什么很多时候开启了 tcp_tw_recycle 也并没有产生问题
背景及现象
服务器:公网服务器
客户端:外网手游客户端
玩家侧现象:大批处于同一局域网内的内侧玩家连接服务器超时,但是切换成 4G 之后连接顺畅。
服务端现象:netstat -s"
显示 “passive connections rejected because of time stamp” 数量增长快速,关闭 tcp_tw_recycle
或 tcp_timestamps
恢复正常,玩家侧现象消失。
问题原因
tcp_tw_recycle
依赖于 tcp_timestamps
, 前者默认关闭,后者默认开启。如果二者都开启,当服务器收到 FIN 包时,这个 FIN 包中的时间戳值会按 IP 缓存起来(缓存 TCP_PAWS_MSL
, 即 60s),缓存时间内,当同一 IP 的 SYN 包时间戳小于该值,则直接丢弃。代码分析如下:
tcp_v4_conn_request()
/* VJ's idea. We save last timestamp seen * from the destination in peer table, when entering * state TIME-WAIT, and check against it before * accepting new connection request. * * If "isn" is not zero, this request hit alive * timewait bucket, so that all the necessary checks * are made in the function processing timewait state. */if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle && (dst = inet_csk_route_req(sk, req)) != NULL && (peer = rt_get_peer((struct rtable *)dst)) != NULL && peer->v4daddr == saddr) { if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && (s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); goto drop_and_release; }}
由于 peer->tcp_ts_stamp
记录的是之前收到 FIN 包时服务器的时间戳,peer->tcp_ts
记录的是 FIN 包中的时间戳,req->ts_recent
表示当前 SYN 包中的时间戳,因此 (u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL
表示缓存还未过期,(s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW
表示当前 SYN 包中的时间戳比之前 FIN 包中的时间戳还小 1s, 因此认为当前 SYN 包时之前重传的,直接丢弃。
req - struct request_sock
peer- struct inet_peer, inet_getpeer()
get_seconds() - 获取当前服务器时间
TCP_PAWS_MSL
#define TCP_PAWS_MSL 60 /* Per-host timestamps are invalidated * after this time. It should be equal * (or greater than) TCP_TIMEWAIT_LEN * to provide reliability equal to one * provided by timewait state.
TCP_PAWS_WINDOW
#define TCP_PAWS_WINDOW 1 /* Replay window for per-host * timestamps. It must be less than * minimal timewait lifetime. */
tcp_v4_tw_remember_stamp()
int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw){ struct inet_peer *peer = inet_getpeer(tw->tw_daddr, 1); if (peer) { const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 || ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) { peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp; peer->tcp_ts = tcptw->tw_ts_recent; } inet_putpeer(peer); return 1; } return 0;}
peer->tcp_ts_stamp
同 tcptw->tw_ts_recent_stamp
, peer->tcp_ts
同 tcptw->tw_ts_recent
, 见 tcp_timewait_state_process()
.
tcptw - struct tcp_timewait_sock, struct inet_timewait_sock
tcp_timewait_state_process()
/* FIN arrived, enter true time-wait state. */tw->tw_substate = TCP_TIME_WAIT;tcptw->tw_rcv_nxt = TCP_SKB_CB(skb)->end_seq;if (tmp_opt.saw_tstamp) { tcptw->tw_ts_recent_stamp = get_seconds(); tcptw->tw_ts_recent = tmp_opt.rcv_tsval;}/* I am shamed, but failed to make it more elegant. * Yes, it is direct reference to IP, which is impossible * to generalize to IPv6. Taking into account that IPv6 * do not understand recycling in any case, it not * a big problem in practice. --ANK */if (tw->tw_family == AF_INET && tcp_death_row.sysctl_tw_recycle && tcptw->tw_ts_recent_stamp && tcp_v4_tw_remember_stamp(tw)) inet_twsk_schedule(tw, &tcp_death_row, tw->tw_timeout, TCP_TIMEWAIT_LEN);else inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN, TCP_TIMEWAIT_LEN);return TCP_TW_ACK;
从此处可以看出,tcptw->tw_ts_recent_stamp
记录的是收到 FIN 包时服务器当前时间,而 tcptw->tw_ts_recent
记录的是 FIN 包中对端的时间戳。
结论
由于大量内侧玩家位于同一 NAT 网络中,所有玩家的 IP 被转换成同一出口 IP, 但时间戳却保留,因此到达服务器的包中时间戳顺序跟到达顺序是不一致的,当同时开启 tcp_tw_recycle
和 tcp_timestamps
时,一个玩家断开连接可能导致其他玩家的 SYN 包被丢弃掉。
实践
如何配置 tcp_tw_recycle 和 tcp_timestamps
tcp_timestamp
建议开启。tcp_timestamp
是 RFC1323 定义的优化选项,主要用于 TCP 连接中 RTT(Round Trip Time) 的计算,开启 tcp_timestamp
有利于系统计算更加准确的 RTT,也就有利于 TCP 性能的提升。
tcp_tw_recycle
建议关闭。
多数系统的默认设置也是如此。
为什么很多时候开启了 tcp_tw_recycle 也并没有产生问题
一是现网中很少出现批量用户处于同一 NAT 网络中且包被 NAT 网关转发之后顺序错乱,即使出现数量也很少;
二是有些客户端系统并没有使用时间戳,例如 XP 和多数 Windows 7.
- 公网服务器或客户端为 NAT 网络的服务器不要同时开启 tcp_tw_recycle 和 tcp_timestamps
- tcp_timestamps tcp_tw_recycle引起的服务器连接不上问题
- tcp_tw_recycle和tcp_timestamps的文章汇总
- 网络编程 一个服务器同时为多个客户端服务
- [转]NAT网络下TCP连接建立时可能SYN包被服务器忽略-tcp_tw_recycle
- NAT网络下TCP连接建立时可能SYN包被服务器忽略-tcp_tw_recycle
- NAT网络下TCP连接建立时可能SYN包被服务器忽略-tcp_tw_recycle
- NAT网络下TCP连接建立时可能SYN包被服务器忽略-tcp_tw_recycle
- tcp_tw_recycle和tcp_timestamps导致connect失败问题
- tcp_tw_recycle和tcp_timestamps导致connect失败问题
- tcp_tw_recycle和tcp_timestamps导致connect失败问题
- tcp_tw_recycle和tcp_timestamps导致connect失败问题
- tcp_tw_recycle和tcp_timestamps导致connect失败问题
- tcp_tw_recycle和tcp_timestamps导致connect失败问题
- tcp_tw_recycle和tcp_timestamps导致connect失败问题
- tcp_tw_recycle和tcp_timestamps导致connect失败问题
- tcp_tw_recycle检查tcp_timestamps的内核代码
- Linux网络编程 之 TCP 多线程的服务器和客户端同时收发数据
- MySQL--修改数据表5:删除主键约束,唯一约束,外键约束
- 反射工具类(调用父类的方法和字段)
- c语言运算符优先级
- Servlet基础
- [LeetCode] Maximum Subarray 求连续子数组的最大和
- 公网服务器或客户端为 NAT 网络的服务器不要同时开启 tcp_tw_recycle 和 tcp_timestamps
- 朴素贝叶斯分类器及Python实现
- 有序广播案例实现
- 原生JS添加删除Class
- Zurmo(十五)之图标四
- UIView周边加阴影,并且同时圆角
- 人人网面试经历
- LibSVM for Python 使用
- 面向对象软件工程概述复习题