我正在创建一个基于 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/