关闭连接后无法通过本地端口连接

Posted

技术标签:

【中文标题】关闭连接后无法通过本地端口连接【英文标题】:Cannot connect via local port after closing connection 【发布时间】:2012-06-19 22:11:49 【问题描述】:

我正在尝试按照本文http://www.brynosaurus.com/pub/net/p2pnat/ 中的描述对 NAT 的 TCP 打孔进行原型设计。

我有一段简单的代码尝试在特定本地端口上打开与服务器的连接。我正在尝试在公共服务器上观察 NAT 是否将两个连接都映射到同一个 NAT 映射。

int localPort = getFreeLocalPort();

     while (true) 

        Socket connection = new Socket(_publicServerHost,_publicServerPort,
                 getLocalSocketAddress(), localPort);

        connection.setReuseAddress(true);

        connection.close();

     

第一次连接正常。但是第二次尝试它会引发异常:

为打孔选择的本地端口:65416

2012-06-17 15:55:21,545 错误 - 地址已在使用中:连接

2012-06-17 15:55:25,175 调试 - 详细信息: java.net.BindException:地址已在使用:连接 在 java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.6.0_24] 在 java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351) ~[na:1.6.0_24] 在 java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213) ~[na:1.6.0_24] 在 java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200) ~[na:1.6.0_24] 在 java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) ~[na:1.6.0_24] 在 java.net.Socket.connect(Socket.java:529) ~[na:1.6.0_24] 在 java.net.Socket.connect(Socket.java:478) ~[na:1.6.0_24] 在 java.net.Socket.(Socket.java:375) ~[na:1.6.0_24] 在 java.net.Socket.(Socket.java:249) ~[na:1.6.0_24]

【问题讨论】:

【参考方案1】:

尝试在 connection.close(); 之前直接添加connection.setSoLinger(true, 0);

像这样:

connection.setSoLinger(true, 0);
connection.close();

这会强制操作系统释放套接字。

【讨论】:

并丢弃任何待发送的数据...不推荐。 if(connection.isConnected() && connection.isBound()) connection.setSoLinger(true, 0);连接.close();但我得到一个 java.net.SocketException: Socket is closed 异常 @pkrish Socket.isConnected() 只告诉您是否已连接套接字。 Socket.isBound() 只告诉你是否绑定了套接字。既不告诉您您是否已关闭套接字,也不告诉您对等方何时关闭。在任何情况下,您都在用这一切完全吠叫错误的树。看我的回答。 @dantuch 我在不同网络中的另一台机器上尝试了 setSoLinger 选项,它似乎有效。虽然我最多可以连接 10 个连接,但这很好。我在两台机器上都使用 Windows 7,所以我无法理解不同的行为。可能是 NAT 行为不同?【参考方案2】:

选择本地端口的依据是什么?显然不是一个健全的人。如果需要的话,最好让系统选择它,方法是指定零,并在打开套接字后从 获取实际值。

【讨论】:

getFreeLocalPort() 方法获取一个空闲的本地端口。 ServerSocket 服务器 = 新的 ServerSocket(0); int port = server.getLocalPort(); @pkrish 错误,但很明显,它没有获得一个免费的本地端口,因为它选择了一个仍在 TIME_WAIT 中的端口。我所描述的技术获得一个具有 100% 可靠性的免费本地端口。 我想通过同一个本地端口建立多个连接。即处于 TIME_WAIT 状态的端口。连接.setReuseAddress(true);应该让你这样做。这样做的原因是为了实现TCP打孔。如果您阅读我链接到的论文(第 4.1 节),它会更详细地解释它。 @pkrish setSoLinger() 并不是“打算做”任何这样的事情。这只是一种重置连接的方式,除此之外,这对 TCP 连接来说是一件坏事,因为您可能会丢失数据。当你按照我的方式尝试时发生了什么? 按照你的方法,我会得到相同的行为,因为我会在 TIME_WAIT 周期之前重用端口。我想我应该让服务器关闭连接,因为这会阻止客户端套接字进入 TIME_WAIT。【参考方案3】:

你的问题解决了吗? 应该在分配端口之前调用 setReuseAddress()。

Socket connection = new Socket();
connection.setReuseAddress(true);
connection.bind( ...);

【讨论】:

以上是关于关闭连接后无法通过本地端口连接的主要内容,如果未能解决你的问题,请参考以下文章

redis通过6379端口无法连接服务器

通过 SSH 隧道的 Java Swing 应用程序 MySQL 连接失败,并显示“本地端口 127.0.0.1:...无法绑定...地址已在使用中:JVM_Bind”

Mysql无法远程连接,本地通过sqlyog无法连接

如何关闭Mysql打开的3306端口防止系统被入侵

TCP关闭链接之TIME_WAIT

本地oracle可以通过localhost连接,无法通过ip地址连接解决方法,oracle远程连接配置