我正在使用 MVC 架构在 javafx 中编写电子邮件应用程序。 服务器的启动方法是这样的
@Override
public void run() {
try {
serverSocket = new ServerSocket(PORT);
controller.logEvent(Protocol.SERVER_STARTED, true, null, null);
loadAccounts();
while (isRunning.get()) {
try {
Socket socket = serverSocket.accept();
if (isRunning.get()) {
connectedClients.add(socket);
Thread thread = new Thread(() -> {
handleClient(socket);
connectedClients.remove(socket);
});
thread.start();
} else {
socket.close();
}
} catch (SocketException e) {
if (!isRunning.get()) {
break;
} else {
throw e;
}
}
}
} catch (IOException e) {
controller.logEvent(Protocol.SERVER_STARTED, false, null, null);
e.printStackTrace();
}
}
而停止服务器的是这样的:
public void stopServer() {
isRunning.set(false);
try {
if (serverSocket != null) {
serverSocket.setReuseAddress(true);
serverSocket.close();
controller.logEvent(Protocol.SERVER_STOPPED, true, null, null);
for (Socket socket : connectedClients) {
socket.close();
}
connectedClients.clear();
}
} catch (IOException e) {
controller.logEvent(Protocol.SERVER_STOPPED, false, null, null);
e.printStackTrace();
}
}
Il mio problema risiede nella ripartenza del server。 Quando provo a farlo ripartire, mi da' questi errori:
java.net.BindException: Address already in use (Bind failed)
at java.base/java.net.PlainSocketImpl.socketBind(Native Method)
at java.base/java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:452)
at java.base/java.net.ServerSocket.bind(ServerSocket.java:395)
at java.base/java.net.ServerSocket.<init>(ServerSocket.java:257)
at java.base/java.net.ServerSocket.<init>(ServerSocket.java:149)
at MailServer.run(MailServer.java:71)
at java.base/java.lang.Thread.run(Thread.java:829)
我重启服务器的方法是这样的:
public void startServer() {
try {
if (serverSocket != null && !serverSocket.isClosed()) {
serverSocket.setReuseAddress(true);
serverSocket.close();
}
isRunning.set(true);
serverSocket = new ServerSocket(PORT);
Thread thread = new Thread(this);
thread.start();
controller.logEvent(Protocol.SERVER_STARTED, true, null, null);
} catch (IOException e) {
controller.logEvent(Protocol.SERVER_STARTED, false, null, null);
}
}
你有什么建议可以解决我的问题吗?我发现问题是服务器停止时端口没有释放,但我不知道如何解决它。
REUSEADDR 不是关于在关闭时“释放”地址,而是关于允许绑定到正在使用的地址。地址(端口)will 在套接字关闭后被某些人“使用”,这就是协议必须工作的方式。
当您最初在“运行”方法中绑定套接字时,您创建它时没有使用 REUSEADDR,这就是您的异常来源。
我不太熟悉 Java 服务器套接字(但有 C 套接字的经验),但是文档说你想做的是
创建一个未绑定的套接字(使用无参数构造函数)
设置重用地址
将套接字绑定到接口和端口
按照这个顺序。不要理会关闭时间的事情,但每次创建新的 ServerSocket 时都这样做。