3

我正在创建一个基于 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 文件中正确存储和更改。但是当我更改我的套接字并通过该套接字立即导航到一个页面时,它说它已关闭并且在我重新启动我的应用程序之前无法工作。

我仍在寻找一种方法来规避这种重启。


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

感谢您的回复和东西。

4

2 回答 2

2

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

引用方法的javadocsetReuseAddress

当 TCP 连接关闭时,连接可能会在连接关闭后的一段时间内保持超时状态(通常称为 TIME_WAIT 状态或 2MSL 等待状态)。对于使用众所周知的套接字地址或端口的应用程序,如果存在涉及套接字地址或端口的处于超时状态的连接,则可能无法将套接字绑定到所需的 SocketAddress。

在使用 bind(SocketAddress) 绑定套接字之前启用 SO_REUSEADDR 允许绑定套接字,即使先前的连接处于超时状态。

于 2012-12-12T11:14:25.013 回答
2

使用TCPview查看系统中所有打开的端口。您可以关闭那些正在使用的端口。

于 2012-12-12T11:45:56.690 回答