Java 有效地停止服务器套接字
我是网络新手,我一直在玩Java中的套接字。我想知道停止服务器套接字的最佳方法是什么。使用当前代码,我得到以下错误:Java 有效地停止服务器套接字,java,networking,Java,Networking,我是网络新手,我一直在玩Java中的套接字。我想知道停止服务器套接字的最佳方法是什么。使用当前代码,我得到以下错误: java.net.SocketException: socket closed [13:30:50] [pool-4-thread-1/WARN]: at java.net.DualStackPlainSocketImpl.accept0(Native Method) [13:30:50] [pool-4-thread-1/WARN]: at java.net.DualSt
java.net.SocketException: socket closed
[13:30:50] [pool-4-thread-1/WARN]: at java.net.DualStackPlainSocketImpl.accept0(Native Method)
[13:30:50] [pool-4-thread-1/WARN]: at java.net.DualStackPlainSocketImpl.socketAccept(Unknown Source)
[13:30:50] [pool-4-thread-1/WARN]: at java.net.AbstractPlainSocketImpl.accept(Unknown Source)
[13:30:50] [pool-4-thread-1/WARN]: at java.net.PlainSocketImpl.accept(Unknown Source)
[13:30:50] [pool-4-thread-1/WARN]: at java.net.ServerSocket.implAccept(Unknown Source)
[13:30:50] [pool-4-thread-1/WARN]: at java.net.ServerSocket.accept(Unknown Source)
[13:30:50] [pool-4-thread-1/WARN]: at io.bluecube.worldlink.DataListener.run(DataListener.java:35) //<------------------------
[13:30:50] [pool-4-thread-1/WARN]: at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
[13:30:50] [pool-4-thread-1/WARN]: at java.util.concurrent.FutureTask.run(Unknown Source)
[13:30:50] [pool-4-thread-1/WARN]: at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
[13:30:50] [pool-4-thread-1/WARN]: at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
[13:30:50] [pool-4-thread-1/WARN]: at java.lang.Thread.run(Unknown Source)
有没有更好的方法来关闭它?谢谢 您的问题是,除非另有规定,
accept()
方法将无限期地阻塞。因此,是的,在accept()
阻塞时关闭套接字会导致出现问题
因此,首先在服务器套接字上调用setSortimeout()
。这将使accept()
仅阻塞N毫秒。。。在此之后,它将抛出一个您必须处理的SocketTimeoutException
,但这允许您有效地将其放入循环中-只需在每次运行结束时重新提交您的Runnable
。如果池已关闭,您将无法重新提交,您将知道您已经完成了
接下来,在对池调用shutdown()
之后,需要等待池实际关闭。使用池上的waittermination()
,然后可以关闭ServerSocket
当然,这方面有很多变化——您可以保持while()
循环,并设置某种标志,等等——任何您最满意的方式。我上面提供的大纲只是我脑海中的第一件事,对你来说可能并不完美,但希望能为你指明方向。试图回答:
有没有更好的方法来关闭它
不要使用!Thread.currentThread().isInterrupted()
作为您的条件,因为它不可靠
为什么?
首先,请参见(阅读)中的,关于shutdown()
和shutdownNow()
它指出:
此方法不会等待主动执行的任务终止。使用此选项可以完成此操作
另外,对于shutdownNow()
:
除了尽最大努力尝试停止处理积极执行的任务之外,没有其他保证。例如,典型的实现将通过Thread.interrupt()取消,因此任何未能响应中断的任务可能永远不会终止
因此,调用pool.shutdownNow()代码>可能有也可能没有(立即)效果。它也是一个非阻塞调用,这意味着this.serverSocket.close()代码>可能在任何其他线程继续执行之前执行
也可能发生线程A计算!Thread.currentThread().isInterrupted()
,然后挂起以让线程B继续。线程B运行关闭(!)服务器套接字的shutdown()
方法。当线程A恢复时,服务器套接字
关闭。-您不应假定任何特定的执行顺序。
您根本不知道/无法控制DataListener
线程何时中断。事实上,根据您的实现(//stuff
),它们可能永远不会被中断
那现在怎么办?
- 将从
serverSocket.accept()获取的新Socket
实例传递给DataListener
线程,而不是在多个线程之间共享serverSocket
李>
- 将
serverSocket
与shutdown()
方法以及serverSocket.accept()上的“while true循环”阻塞保持在同一类(线程)中:
pool.execute(新的DataListener(serverSocket.accept())代码>
- (考虑为您的
服务器套接字定义超时时间
)
通过这种方式,您只能为已连接的套接字
实例启动一个DataListener
线程。使用该连接执行//填充
,然后关闭该线程中的套接字
实例
public class DataListener implements Runnable {
private final Socket receive;
public DataListener(final Socket receive){
this.receive = receive;
}
@Override
public void run() {
// do stuff with your connected socket
// do proper resource/exception handling
// close the socket here
}
}
这种方法和任何方法一样好,而且比设置短超时和每次触发时检查布尔值的最佳替代方法更快、更少地浪费CPU。
private ExecutorService pool = Executors.newCachedThreadPool();
private ServerSocket serverSocket;
//stuff
public void shutdown() throws InterruptedException{
pool.shutdownNow();
if (!serverSocket.isClosed()){
try {
this.serverSocket.close();
} catch(IOException e1) {
e1.printStackTrace();
}
}
if (pool.awaitTermination(10, TimeUnit.SECONDS)){
System.out.println("Terminated");
}
}
public class DataListener implements Runnable {
private final Socket receive;
public DataListener(final Socket receive){
this.receive = receive;
}
@Override
public void run() {
// do stuff with your connected socket
// do proper resource/exception handling
// close the socket here
}
}