我有一个带有此代码的服务器线程:
public void run() {
try {
ServerSocket server;
EneaLog.printLog("Server is running.");
server = new ServerSocket(this.portnumber);
while (true) {
new EneaServerConnection(server.accept(), this.project,stopped).start();
if (stopped) {
EneaLog.printLog("Server safe-shutdown completed.");
EneaLog.printLog("Hi!");
server.close();
return;
}
}
} catch (IOException ex) {
Logger.getLogger(EneaServer.class.getName()).log(Level.SEVERE, null, ex);
project.getExceptionHandler().handler(ex);
}
}
和这样的关机方法:
public void shutdown() {
EneaLog.printLog("Server shutdown NOW!");
stopped = true;
}
我希望关闭可以解除在server.accept()上等待的线程,否则我必须在服务器关闭之前等待连接。
我不能在shutdown()中执行server.close(),因为我必须向注册客户端发信号通知服务器正在关闭。
有什么想法吗?
答案 0 :(得分:4)
我尝试设计我的代码,以便它可以通过中断“关闭”。主要是因为Java的并发包中的Executor
框架使用interrupt
来取消正在运行的任务。此外,“关闭”任务不必知道正在被杀死的任务的任何内部。
然而,对accept
的调用不会响应中断,除非它是created from a ServerSocketChannel
.使用ServerSocket
构造函数创建的服务器将忽略中断,并且我还没有找到重新配置它的方法。
如果您无法更改创建服务器的代码,请安排另一个线程在服务器套接字上调用close
。无论用于创建服务器套接字的方法如何,这也会在accept
上阻塞的线程中引发异常。
使用SSL时,这是一个非常大的痛苦。 JSSE套接字不是从InterruptibleChannel
创建的,并且不会响应线程上的简单中断。
我刚刚注意到问题是在没有通知客户端的情况下无法关闭服务器。成功中断套接字会导致其关闭。
在调用accept
时,这应该不是问题,因为如果服务器套接字在accept中被阻止,则客户端未连接。这应该只是代表当前连接的Socket
个实例的问题。
如果不满足通知要求,可能需要在非阻塞模式下使用NIO的ServerSocketChannel
进行返工。
答案 1 :(得分:2)
您应该能够从另一个线程关闭套接字。
答案 2 :(得分:2)
中断(取决于取消取决于取消点的中断点取决于中断点)也不会关闭(接受不响应关闭其文件描述符)。您必须与accept进行通信(尝试sendto,并发出关闭通知)以通知它不继续接受。至少在linux上就是这种情况;不知道在其他平台上是什么样的。
答案 3 :(得分:1)
我一直面临着同样的问题。我的工作解决方案包括关闭ServerSocket对象(serverSocket.close());这样做会导致accept()方法抛出一个SocketException,这就是你想要做的。
文森特
答案 4 :(得分:0)
您是否尝试过Thread.interrupt()?
如果此线程在I / O中被阻止 对可中断的操作 然后通道将是通道 关闭,线程的中断状态 将被设置,线程将 收到ClosedByInterruptException。
如果此线程被阻止 然后选择线程的中断 状态将被设置,它将返回 立即从选择 操作,可能是非零 值,就像选择器一样 唤醒唤醒方法。