java关闭serversocket并打开端口

标签 java timeout serversocket

我正在创建一个基于 Java 的服务器。

我正在使用服务器套接字来接受传入的消息。

但是在我的程序中的某个时刻,我希望服务器套接字监听另一个端口。

我关闭服务器套接字。并用我的新端口开始一个新的。一切都很好。

然而,当我再次将服务器套接字更改为之前的端口时,它会给我一个错误。

我读过服务器套接字在我关闭后会保持一段时间的超时状态。

所以这是我的问题: 我能否绕过服务器套接字的这种超时状态,并在我关闭它并想再次收听同一端口后使我的端口再次可用?


编辑:我创建和监听服务器套接字的功能以及我使服务器套接字无效并在之后立即创建新套接字的功能

public void makeServerSocketWithPort(int portnr) throws IOException, Exception
{
    server = new ServerSocket(portnr);
    server.setReuseAddress(true);
    while(!portchanged)
    {
        Socket sock = server.accept();
        System.out.println(server.getLocalPort());
        System.out.println(sock.getLocalPort());
        handler = new Requesthandler(sock); //should be in a thread
        System.out.println(server.getLocalPort());
        System.out.println(sock.getLocalPort());
    }
    
}

public void invalidateRequestHandler(int newPort)
{   
    if(server != null)
    {
       portchanged = true; 
        try {
            server.close();
        } catch (IOException ex) {
            Logger.getLogger(Controlserver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    portchanged = false;
    makeServerSocketWithPort(newPort);
}

错误堆栈跟踪:

Exception in thread "main" java.net.SocketException: Socket closed
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
at java.net.ServerSocket.implAccept(ServerSocket.java:462)
at java.net.ServerSocket.accept(ServerSocket.java:430)
at stuff.Controlserver.makeServerSocketWithPort(Controlserver.java:63)
at stuff.Main.main(Main.java:44)

编辑: 第二次尝试修复它无济于事:

public void makeServerSocketWithPort(int portnr, boolean invalidated) throws IOException, Exception
{
    if(!invalidated)
    {
        server = new ServerSocket();
        server.setReuseAddress(true);
        server.bind(new InetSocketAddress(portnr));

        portchanged = false;
    }
    else
    {
        //TODO: invalidate the old requestHandler
        if(server != null)
        { 
            try 
            {
                server.close();
                server = null;
            } 
            catch (IOException ex) 
            {
                Logger.getLogger(Controlserver.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if(server.isClosed())
        {
            System.out.println("closed biatch!");
        }
        else
        {
            System.out.println("surprise moddafakkaaaaa!!!");
        }

        //---------------------------------------------
        //then make new requestHandler with new port
        portchanged = true;
    }
    
    while(!portchanged)
    {
        if(server != null && !server.isClosed() && !invalidated)
        {
            Socket sock = server.accept();
            System.out.println(server.getLocalPort());
            System.out.println(sock.getLocalPort());
            System.out.println("test");
            handler = new Requesthandler(sock); //should be in a thread
            handler.start();
            System.out.println("ja harm");
            System.out.println(server.getLocalPort());
            System.out.println(sock.getLocalPort());
        }
        else
        {
            portchanged = true;
        }
    }
    
    if(portchanged)
    {
        portchanged = false;
        makeServerSocketWithPort(portnr, false);
    }
}

再次正常工作。我可以浏览我的 html 页面。当我通过其中一个网页更改我的端口号时,它会在我的存储 xml 文件中正确存储和更改。 但是当我更改我的套接字并立即通过该套接字导航到一个页面时,它说它已关闭并且在我重新启动我的应用程序之前无法工作。

我仍在寻找避免重启的方法。


好吧,我解开了这个谜团。 事情是我只需要稍微重建我的类以更好地支持线程。我没有关闭套接字然后创建一个新线程,而是启动了一个新线程然后关闭了套接字。经过一些摆弄后,它似乎工作得很好。

最佳答案

这是操作系统的正常服务器套接字行为。操作系统使端口在 WAIT_TIMEOUT 状态下保持打开状态。要解决此问题,请尝试使用 ServerSocket.setReuseAddress(boolean on)。这将启用/禁用 SO_REUSEADDR 套接字选项。 Check here用于文档。

引用方法setReuseAddress的javadoc

When a TCP connection is closed the connection may remain in a timeout state for a period of time after the connection is closed (typically known as the TIME_WAIT state or 2MSL wait state). For applications using a well known socket address or port it may not be possible to bind a socket to the required SocketAddress if there is a connection in the timeout state involving the socket address or port.

Enabling SO_REUSEADDR prior to binding the socket using bind(SocketAddress) allows the socket to be bound even though a previous connection is in a timeout state.

关于java关闭serversocket并打开端口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13838256/

相关文章:

javascript - Strope.js 客户端连接到服务器,断开连接/超时

Java套接字绑定(bind)抛出异常但工作正常

android - 使用 Android 上托管的 HTTP 服务器检索 POST 数据

java - 使用 JDBC 执行多个 SQL 语句 (CRUD)

Linux coreutils超时相对时间还是绝对时间?

Android 套接字不会通过 .connect() 函数连接,只有 new Socket()

Java 网络 - 在同一线程中的不同端口上并行启动多个服务器套接字

java - 空数组到空列表

java - WebSphere 6.1.0.29 上的 http_access.log

Java substring.equals 与 ==