“java.net.BindException:地址已经在使用”当试图创建与上一个使用新线程相同的套接字
我正在Java客户端(线程)连接到服务器以获取Java一些数据。几秒钟后,随机选择的一个客户端(线程)需要被杀死。我关闭了用于与服务器通信的套接字,并让他死亡(通过从run()方法退出)。问题是,当新创建的线程试图创建相同的插座上一个使用(同一地址和同一端口)连接到服务器,我得到:“java.net.BindException:地址已经在使用”当试图创建与上一个使用新线程相同的套接字
java.net.BindException: Address already in use
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:374)
at java.net.Socket.bind(Socket.java:627)
at java.net.Socket.<init>(Socket.java:423)
at java.net.Socket.<init>(Socket.java:319)
代码创建套接字:
private void createNewSocket(InetAddress sIP, int sPort,
InetAddress cIP, int cPort) {
try {
socket = new Socket(sIP, sPort, cIP, cPort);
} catch (IOException e) {
e.printStackTrace();
System.err.println("Socket unsuccessfully created");
}
try {
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
} catch (IOException e) {
e.printStackTrace();
try {
socket.close();
} catch (IOException e2) {
System.err.println("Socket unsuccessfully closed");
}
}
}
public void run() {
createNewSocket(gprsServerIP, Util.PORT_SERVER_PORT,
clientIP, sendPort);
out.println(REQUEST);
try {
serverPort = Integer.parseInt(in.readLine());
TCPClient.serverPort[clientID] = serverPort;
System.out.println("Server port: " + serverPort + '\n' +
"Send port: " + sendPort + '\n');
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
System.err.println("Socket unsuccessfully closed");
}
}
while (true) {
if (clientID == TCPClient.selectedID) {
TCPClient.selectedID = -1;
createNewSocket(gprsServerIP, Util.PORT_SERVER_PORT,
clientIP, sendPort);
out.println(FREE_PORT + serverPort);
try {
socket.close();
} catch (IOException e2) {
System.err.println("Socket unsuccessfully closed");
}
//System.out.println(socket.isClosed());
System.out.println("Port:" + serverPort + " is free");
TCPClient.id[clientID] = -1;
break;
}
}
clientCount--;
}
有可能是客户端套接字仍在CLOSE_WAIT
or TIME_WAIT
status之内。在另一个应用程序可以重新使用它之前,操作系统正在确保所有数据已经传递到套接字中。否则,新客户端可能会从上一次连接中得到垃圾重复数据包。
我建议你的客户使用一系列端口而不是常数。然后他们可以使用范围中的下一个端口,并在到达范围的末尾时循环。
但是,如果您不需要设置客户端端口,则不应通过将端口号0传递给Socket
来在您的代码中设置客户端端口。在这种情况下,JDK和操作系统会做正确的事情并为您选择合适的自由端口。
从wikipedia引:
CLOSE-WAIT: 服务器从它完成本地应用程序接收通知。服务器将它的fin发送给客户端。
TIME-WAIT: 表示等待足够的时间以确保远程节点收到其连接终止请求的确认。根据RFC 793,连接可以保持在TIME-WAIT中最多四分钟,即MSL(最大段寿命)。
当进程不自然地死亡时,有时端口不会立即解除绑定,您必须等待几分钟才能使端口可用。如果可能的话,你的程序应该优雅地失败(即使它必须被终止,关闭钩子应该关闭套接字)。
来避免这种情况,谢谢你的回复!我感谢您的帮助! – Renton
连接时,您不必指定客户端IP和客户端端口。如果您忽略它们,它会选择一个可用的端口 – Patrick
您可以发布代码以用于run()方法吗? –
我需要使用它们,因为客户端从Ubuntu上的VM和Windows 7上的服务器上运行,并且我需要指定客户端端口和IP用于其他用途。 – Renton