NAT内部的服务器,Windows可以连接,而Linux/Android连接困难的问题

  • 问题现象:

在网关映射一个端口,到公司内部一台服务器(基于Linux的)的服务端口,发现此服务用Windows(10,中文家庭版)连接很顺畅,而手机、Linux客户端连接非常困难,十有八九连不上。

  • 分析过程

在Windows上用Wireshark抓成功连接的数据包,并在手机端用tcpdump(https://www.androidtcpdump.com/android-tcpdump/downloads)抓失败连接的数据包,经详细对比发现:手机端发出的连接请求数据包的TCP层包头中,比Windows多了tcp_timestamp这个option

Windows数据包Window发出的连接请求数据包

 

Android客户端发出的请求,多了Timstamps Option

这种带有tcp_timestamps的连接请求,收不到服务器的响应(同时在服务器端抓数据包,证明服务器根本没发出连接响应数据包,而不是在路由中途丢失)

用tcpreplay工具包修改这个失败的连接请求(用WireEdit也可以),去掉timestamp option(工具会自动计算包头校验和),并重发这个数据包,可以看到服务器端就有连接响应包发出。

  • 原因剖析及解决方案

尝试:在linux客户端,禁用tcp_timestamps:

echo 0 > /proc/sys/net/ipv4/tcp_timestamps

再试连接,结果很顺畅。

禁用服务端tcp_timestamps,也有同样效果。

最后查资料,原因简单来说是:NAT映射的对外服务,对于服务器来说,所有的client都来自一个IP地址,而服务端又启用了 tcp_timestamps和 tcp_tw_recycle选项;同时,Linux的协议栈实现有这么个逻辑:在以上设置的条件下,60秒内,从同一IP的连接请求,timestamp必须是递增的。如果两个客户端都带有timestamp,由于系统时间一般很难精确同步,则系统时间偏大的那个可以连接进来,小的就无法连入。而没有时间戳的请求,服务端无从判定,就可以连接进来了。

知道原因,问题也就好解决了:

修改服务器的 /etc/sysctl.conf

增加或修改一行:

net.ipv4.tcp_tw_recycle = 0

然后重启服务器,或者执行 sysctl -p 就可以了。

技术细节参考:

http://www.cnxct.com/coping-with-the-tcp-time_wait-state-on-busy-linux-servers-in-chinese-and-dont-enable-tcp_tw_recycle/
http://blog.sina.com.cn/s/blog_781b0c850100znjd.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值