我正在用JavaFX编写一个邮箱应用程序,使用MVC架构. 服务器的启动方法是这样的.

    @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();
        }
    }

我的问题是服务器重启.当我试图重新启动它时,它会给我以下错误:

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对于某些人来说是在使用中,这正是协议必须工作的方式.

当您最初在‘Run’方法中绑定套接字时,您在没有REUSEADDR的情况下创建套接字,这就是您的异常的来源.

我对Java服务器套接字不是很熟悉(但有使用C语言套接字的经验),但是the documentation说您想要做的是

Create an unbound socket (with the no-arguments constructor)
Set REUSEADDR
Bind the socket to an interface and port

按这个顺序.不要担心关闭时间的事情,但每次创建新的ServerSocket时都要这样做.

Java相关问答推荐

Java FFM,如何将Java对象与C struct 链接起来?

收听RDX中用户数据的变化

如何在Javascript中设置文本区域圆角的样式

为什么我要创建一个单独的互斥体/锁对象?

连接Quarkus中的两个异步操作

在JavaFX项目中注册组合框的控件FX验证器时,模块系统出错

为什么不应用类型推断?

Bean定义不是从Spring ApplationConext.xml文件加载的

MySQL数据库中未应用具有Spring数据的唯一约束

Jolt变换JSON数组问题

如何在Cosmos DB(Java SDK)中增加默认响应大小

buildDir:File!&#的getter解决方案是什么?39.被抛弃

来自外部模块的方面(对于Java+Gradle项目)不起作用

Cordova Android Gradle内部版本组件不兼容

如何获得凌空cookies ,并设置它在下一个请求- android

如何使用MapStrCut转换双向链接

如何在Java中使用正则表达式拆分字符串

Java List有一个在一个位置添加多个元素的方法,但我找不到一个在一个位置删除多个元素的方法

如何判断元素计数并在流的中间抛出异常?

java21预览未命名的符号用于try-with-resources