Gáb*_*ták 12 java sockets linux tcp apache-zookeeper
如果你愿意,你可以跳过这个故事.还有一些人可能会感兴趣.
我有一个Java嵌入式ZooKeeper服务器.在单元测试中,我将端口分配给测试服务器.在分配端口之前,我通过打开a来检查它是否未使用ServerSocket,然后关闭它.
它不时发生,在BindException我启动我的服务器时得到的单元测试中(我不能将相同的端口分配给两个服务器,因为我使用文件锁也可以进行互斥).事实证明,原因是,对于端口检查我打开端口,然后我关闭它,它等待一段时间在操作系统级别,直到端口可以重新打开.
但是有一个选项(StandardSocketOptions.SO_REUSEADDR)可以告诉Java套接字,可以重用TIMED_WAIT状态的旧套接字.检查ZooKeeper代码后,它实际上设置为true(请参阅org.apache.zookeeper.server.NIOServerCnxnFactory.configure(InetSocketAddress,int)):
@Override
public void configure(InetSocketAddress addr, int maxcc) throws IOException {
configureSaslLogin();
thread = new Thread(this, "NIOServerCxn.Factory:" + addr);
thread.setDaemon(true);
maxClientCnxns = maxcc;
this.ss = ServerSocketChannel.open();
ss.socket().setReuseAddress(true);
LOG.info("binding to port " + addr);
ss.socket().bind(addr);
ss.configureBlocking(false);
ss.register(selector, SelectionKey.OP_ACCEPT);
}
Run Code Online (Sandbox Code Playgroud)
然而,我的测试证明它不起作用.我得到BindException(在Linux JDK 1.7.0_60下).
在检查了ServerSocketChannel实现(JDK 1.7.0_60)后,我意识到,这绝不会在linux下工作.见sun.nio.ch.ServerSocketChannelImpl.setOption(SocketOption<T>, T):
public <T> ServerSocketChannel setOption(SocketOption<T> paramSocketOption, T paramT) throws IOException
{
if (paramSocketOption == null)
throw new NullPointerException();
if (!(supportedOptions().contains(paramSocketOption)))
throw new UnsupportedOperationException("'" + paramSocketOption + "' not supported");
synchronized (this.stateLock) {
if (!(isOpen()))
throw new ClosedChannelException();
if ((paramSocketOption == StandardSocketOptions.SO_REUSEADDR) && (Net.useExclusiveBind()))
{
this.isReuseAddress = ((Boolean)paramT).booleanValue();
}
else {
Net.setSocketOption(this.fd, Net.UNSPEC, paramSocketOption, paramT);
}
return this;
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,Net.useExclusiveBind()在Linux下永远不会给予回报,如果你在希望类似的OpenJDK中检查它的来源,它取决于Net.isExclusiveBindAvailable()Linux下的-1.
在ServerSocket没有SO_REUSEADDR并检查我是否得到的情况下,除了打开没有SO_REUSEADDR 的端口之外,在Java中有没有办法等到端口真正原封闭BindException?当然这不是解决方案,因为那时我必须再次关闭该ServerSocket.为什么在Java中没有像在闭锁模式下关闭套接字一样,只有当套接字真的在操作系统级别关闭时才会返回?
恐怕您对sun.nio.ch.ServerSocketChannelImpl.setOption(SocketOption<T>, T)实施的分析不正确。
“独占绑定”内容仅在 Windows 上使用,与其他平台无关。您可以在sun.nio.ch.Net 类的源代码中检查这一点。具体可以看评论isExclusiveBindAvailable()。
当独占绑定不可用时,ServerSocketChannelImpl.setOption只需调用Net.setSocketOption最终将调用本机setsockopt函数。
顺便说一句,服务器端套接字可能不处于 TIME_WAIT 状态,但也处于 FIN_WAIT_1 或 FIN_WAIT_2 (等待客户端确认关闭)。对 TCP 状态机的深入描述可能会有所帮助。
| 归档时间: |
|
| 查看次数: |
789 次 |
| 最近记录: |