我是网络新手,我一直在玩Java中的套接字。我想知道停止ServerSocket的最佳方法是什么。使用我当前的代码,我收到以下错误:
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)
错误指向我的DataListener类中的这一行:
public class DataListener implements Runnable{
private ServerSocket socket;
public DataListener(ServerSocket socket){
this.socket = socket;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()){
try {
Socket receive = socket.accept(); //<---- Error
//stuff
此runnable在线程池中运行。目前我用以下内容关闭了所有内容:
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");
}
}
有没有更好的方法来关闭它?谢谢!
答案 0 :(得分:0)
您的问题是,除非另有说明,否则accept()
方法将无限期阻止。所以,是的,在accept()
阻塞时关闭套接字会导致你看到的问题。
首先致电setSoTimeout()
上的ServerSocket
。这将使accept()
仅阻止N毫秒......之后它会抛出一个你必须处理的SocketTimeoutException
,但这可以让你有效地将它放入循环中 - 只需在每次运行结束时重新提交Runnable
即可。如果游泳池已关闭,您将无法重新提交,并且您已经知道您已完成。
接下来,在池上调用shutdown()
之后,您需要等待池实际关闭。在池中使用awaitTermination()
,然后您可以关闭ServerSocket
。
当然,有很多变化 - 您可以保持while()
循环并设置某种标志等 - 无论您最熟悉的是什么。我上面提到的大纲只是我想到的第一件事,它可能不适合你,但希望能为你指路。
答案 1 :(得分:0)
试着回答:
有没有更好的方法来关闭它?
请勿使用!Thread.currentThread().isInterrupted()
作为您的条件,因为它不可靠。
<强> 为什么? 强>
首先,请查看(阅读)shutdown()
,shutdownNow()
及其shutdownNow()
:
此方法不等待主动执行任务终止。使用awaitTermination来做到这一点。
另外还有pool.shutdownNow();
:
除了尽力尝试停止处理主动执行任务之外,没有任何保证。例如,典型的实现将通过Thread.interrupt()取消,因此任何无法响应中断的任务都可能永远不会终止。
因此,调用this.serverSocket.close();
可能会或可能不会产生(立即)效果。它也是一个非阻塞调用,这意味着!Thread.currentThread().isInterrupted()
可能会在任何其他线程继续执行之前执行。
也可能发生 线程A评估shutdown()
然后被暂停以让线程B继续。线程B运行serverSocket
方法关闭(!)serverSocket
。线程A恢复时,DataListener
已关闭。 - 您不应该假设任何特定的执行顺序。
您根本不知道/控制//stuff
线程何时被中断。实际上,根据您的实施(serverSocket
),它们可能永远不会被中断。
那么现在呢?
Socket
,而是将您从serverSocket.accept()
到DataListener
个主题的新serverSocket
实例传递给您。 将shutdown()
与serverSocket.accept()
方法保持在同一个类(主题)中,并将pool.execute(new DataListener(serverSocket.accept()));
上的“while-true-loop”阻止与<{1}}保持一致:
serverSocket
DataListener
定义超时。)通过这种方式,您只为已连接的Socket
实例启动// stuff
个线程。使用该连接执行Socket
,然后关闭该线程中的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
}
}
实例。
try {
...
}
catch (IOException e) {
connection.getErrorStream().close();
}