Java网络服务器和TIME_WAIT
我在接收来自我公司生产的设备的信号的网络服务器方面遇到了问题。 设备偶尔会重用刚刚使用过的源端口。 这会导致 SYN 被服务器丢弃。 然后设备会重试,直到旧套接字超出服务器上的 TIME_WAIT 状态。 然后服务器发送 SYN-ACK。
服务器是用Java编写的。 不幸的是,修改设备以正确地循环端口并不是一种选择,因为现场有很多设备,并且更新现有单元也不是一种选择。 旧软件是用 C++ 编写的,并以某种方式从 Windows TCP 堆栈的列表中删除了 TIME_WAIT 端口。
任何人都可以给我提供有关如何在 Windows 上绕过 Java TIME_WAIT 的建议吗?
编辑:我确实在 Wireshark 中确认该设备正在重用最近使用过的端口。
在服务器套接字上,我使用以下选项:
socket = new ServerSocket();
socket.setPerformancePreferences(3, 2, 1);
socket.setReuseAddress(true);
socket.setSoTimeout(CLIENT_READ_TIMEOUT);
socket.bind(new InetSocketAddress(group.getPort()), MAX_TCP_BACKLOG);
客户端套接字在接收后具有以下设置:
Socket client = server.accept();
client.setKeepAlive(false);
client.setSoLinger(true, 0);
client.setReuseAddress(true);
client.setTcpNoDelay(true);
client.setSoTimeout(CLIENT_READ_TIMEOUT);
我已将 SO_LINGER 尝试为 true 和 false,具有完全相同的跟踪结果。 CLIENT_READ_TIMEOUT 设置为 10 秒。
I have run into a problem with a network server that receives signals from devices my company produces. The device will occasionally reuse the source port that it had just used. This causes the SYN to be dropped by the server. The device then retries until the old socket falls out of TIME_WAIT on the server. The server then SYN-ACKs.
The server is written in Java. Unfortunately, modifying the device to cycle ports correctly is not an option, as there are many in the field, and updating the existing units is not an option. The old software was written in C++ and somehow expunged the TIME_WAIT port from the list in the Windows TCP stack.
Can anyone offer me any advice on how to circumvent TIME_WAIT from Java on Windows?
EDIT: I have indeed confirmed in Wireshark that the device is reusing a recently used port.
On the server socket I am using the following options:
socket = new ServerSocket();
socket.setPerformancePreferences(3, 2, 1);
socket.setReuseAddress(true);
socket.setSoTimeout(CLIENT_READ_TIMEOUT);
socket.bind(new InetSocketAddress(group.getPort()), MAX_TCP_BACKLOG);
And the client socket has the following set after receiving:
Socket client = server.accept();
client.setKeepAlive(false);
client.setSoLinger(true, 0);
client.setReuseAddress(true);
client.setTcpNoDelay(true);
client.setSoTimeout(CLIENT_READ_TIMEOUT);
I have tried SO_LINGER as both true and false, with the exact same trace results. CLIENT_READ_TIMEOUT is set to 10 seconds.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
基于 Nikolai 的答案,
Java 中的答案是等效的。
编辑:您可能想看的另一件事是 setReuseAddress(true);
Building on Nikolai's answer,
would be the equivalent in Java.
EDIT: Another thing you might like to look at would be setReuseAddress(true);
避免
TIME_WAIT
的不推荐老技巧是将SO_LINGER
套接字选项设置为{ 1, 0 }
-close
然后发送RST
而不是执行正常的刷新/四向交换序列,从而避免TIME_WAIT
一起出现(请注意 - 您可能会丢失发送缓冲区中剩余内容的尾部。)不过,我无法评论这是否可以在 Java 中完成。编辑:您可以使用 tcpdump 确认客户端确实重用源端口号吗? 如果不是,这可能只是 Jon 指出的 SO_REUSEADDR 侦听套接字选项的经典案例。
The old not-recommended trick to avoid
TIME_WAIT
is to setSO_LINGER
socket option to{ 1, 0 }
- theclose
then sendsRST
instead of doing normal flush/four-way exchange sequence, thus avoiding theTIME_WAIT
all together (be warned - you might lose tail of what you still have in the send buffer.) I can't comment on whether this could be done in Java though.EDIT: Can you confirm with
tcpdump
that the clients really reuse source port numbers? If not, this might just be the classic case for SO_REUSEADDR listening socket option as Jon pointed out.服务器忽略来自客户端的 SYN 数据包,因为它无法区分使用旧源端口的新会话的数据包和来自旧会话的重传数据包。 如果您通过设置控制块表中超时 TIME_WAIT 状态条目的系统计时器间隔来规避服务器上的 TIME_WAIT 状态,那么您的服务器将如何正确忽略已终止会话的 SYN 重传?
The server is ignoring the SYN packets from the client because it cannot distinguish between those for a new session using the old source port and retransmissions from the old session. If you circumvent the
TIME_WAIT
state on the server, by setting the system timer interval for aging out TIME_WAIT state entries in the control block table, then how will your server properly ignore SYN retransmissions for sessions that have already terminated?