Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何中断ServerSocket accept()方法?_Java_Network Programming - Fatal编程技术网

Java 如何中断ServerSocket accept()方法?

Java 如何中断ServerSocket accept()方法?,java,network-programming,Java,Network Programming,在我的主线程中,我有一个while(listening)循环,它在我的ServerSocket对象上调用accept(),然后启动一个新的客户端线程,并在接受新客户端时将其添加到集合中 我还有一个管理线程,我想用它来发出命令,比如“exit”,它会关闭所有的客户端线程,关闭自己,然后关闭主线程,通过监听false 但是,while(listening)循环中的accept()调用会阻塞,并且似乎没有任何方法中断它,因此无法再次检查while条件,程序也无法退出 有更好的方法吗?或者以某种方式中断

在我的主线程中,我有一个
while(listening)
循环,它在我的ServerSocket对象上调用
accept()
,然后启动一个新的客户端线程,并在接受新客户端时将其添加到集合中

我还有一个管理线程,我想用它来发出命令,比如“exit”,它会关闭所有的客户端线程,关闭自己,然后关闭主线程,通过监听false

但是,
while(listening)
循环中的
accept()
调用会阻塞,并且似乎没有任何方法中断它,因此无法再次检查while条件,程序也无法退出

有更好的方法吗?或者以某种方式中断阻塞方法?

是在
ServerSocket
上调用
close()

关闭此套接字。当前在accept()中阻塞的任何线程都将抛出SocketException


您可以从另一个线程调用,调用将抛出一个。

accept()
上设置超时,然后调用将在指定时间后使阻塞超时:

在阻止
套接字操作时设置超时:

ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();
必须在进入阻塞操作之前设置该选项才能生效。如果超时过期且操作将继续阻塞,则会引发
java.io.InterruptedIOException
。在这种情况下,
插座
不会关闭


您可以尝试的另一个更干净的方法是检查accept循环中的标志,然后当您的管理线程想要终止accept上的线程阻塞时,设置标志(使其成为线程安全的),然后建立到侦听套接字的客户端套接字连接。 accept将停止阻塞并返回新套接字。 您可以解决一些简单的协议问题,告诉侦听线程干净地退出线程。 然后关闭客户端的套接字。
没有异常,更干净。

原因
ServerSocket.close()
是因为您有一个
outputstream
inputstream
连接到那个插座上。 通过首先关闭输入和输出流,可以安全地避免此异常。 然后尝试关闭
ServerSocket
。 以下是一个例子:

void closeServer() throws IOException {
  try {
    if (outputstream != null)
      outputstream.close();
    if (inputstream != null)
      inputstream.close();
  } catch (IOException e1) {
    e1.printStackTrace();
  }
  if (!serversock.isClosed())
    serversock.close();
  }
}
您可以调用此方法从任何位置关闭任何套接字,而不会出现异常。

您只需为break serversocket.accept()创建“void”套接字即可

服务器端

private static final byte END_WAITING = 66;
private static final byte CONNECT_REQUEST = 1;

while (true) {
      Socket clientSock = serverSocket.accept();
      int code = clientSock.getInputStream().read();
      if (code == END_WAITING
           /*&& clientSock.getInetAddress().getHostAddress().equals(myIp)*/) {
             // End waiting clients code detected
             break;
       } else if (code == CONNECT_REQUEST) { // other action
           // ...
       }
  }
void acceptClients() {
     try {
          Socket s = new Socket(myIp, PORT);
          s.getOutputStream().write(END_WAITING);
          s.getOutputStream().flush();
          s.close();
     } catch (IOException e) {
     }
}
中断服务器周期的方法

private static final byte END_WAITING = 66;
private static final byte CONNECT_REQUEST = 1;

while (true) {
      Socket clientSock = serverSocket.accept();
      int code = clientSock.getInputStream().read();
      if (code == END_WAITING
           /*&& clientSock.getInetAddress().getHostAddress().equals(myIp)*/) {
             // End waiting clients code detected
             break;
       } else if (code == CONNECT_REQUEST) { // other action
           // ...
       }
  }
void acceptClients() {
     try {
          Socket s = new Socket(myIp, PORT);
          s.getOutputStream().write(END_WAITING);
          s.getOutputStream().flush();
          s.close();
     } catch (IOException e) {
     }
}

使用。

好的,我用一种更直接的方式解决了OP的问题

请继续阅读简短的答案,以获取我如何使用它的线程示例。

简短答复:

ServerSocket myServer;
Socket clientSocket;

  try {    
      myServer = new ServerSocket(port)
      myServer.setSoTimeout(2000); 
      //YOU MUST DO THIS ANYTIME TO ASSIGN new ServerSocket() to myServer‼!
      clientSocket = myServer.accept();
      //In this case, after 2 seconds the below interruption will be thrown
  }

  catch (java.io.InterruptedIOException e) {
      /*  This is where you handle the timeout. THIS WILL NOT stop
      the running of your code unless you issue a break; so you
      can do whatever you need to do here to handle whatever you
      want to happen when the timeout occurs.
      */
}
现实世界的例子:

在本例中,我有一个ServerSocket在线程内等待连接。当我关闭应用程序时,我希望在让应用程序关闭之前以干净的方式关闭线程(更具体地说,是套接字),因此我在ServerSocket上使用.setSortimeout(),然后使用超时后抛出的中断来检查父线程是否试图关闭线程。如果是这样,那么我设置close套接字,然后设置一个标志指示线程已经完成,然后我中断返回null的Threads循环

package MyServer;

import javafx.concurrent.Task;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

public class Server {

public Server (int port) {this.port = port;}

private boolean      threadDone        = false;
private boolean      threadInterrupted = false;
private boolean      threadRunning     = false;
private ServerSocket myServer          = null;
private Socket       clientSocket      = null;
private Thread       serverThread      = null;;
private int          port;
private static final int SO_TIMEOUT    = 5000; //5 seconds

public void startServer() {
    if (!threadRunning) {
        serverThread = new Thread(thisServerTask);
        serverThread.setDaemon(true);
        serverThread.start();
    }
}

public void stopServer() {
    if (threadRunning) {
        threadInterrupted = true;
        while (!threadDone) {
            //We are just waiting for the timeout to exception happen
        }
        if (threadDone) {threadRunning = false;}
    }
}

public boolean isRunning() {return threadRunning;}


private Task<Void> thisServerTask = new Task <Void>() {
    @Override public Void call() throws InterruptedException {

        threadRunning = true;
        try {
            myServer = new ServerSocket(port);
            myServer.setSoTimeout(SO_TIMEOUT);
            clientSocket = new Socket();
        } catch (IOException e) {
            e.printStackTrace();
        }
        while(true) {
            try {
                clientSocket = myServer.accept();
            }
            catch (java.io.InterruptedIOException e) {
                if (threadInterrupted) {
                    try { clientSocket.close(); } //This is the clean exit I'm after.
                    catch (IOException e1) { e1.printStackTrace(); }
                    threadDone = true;
                    break;
                }
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
};

}

我希望这对以后的人有所帮助。

您只需在调用accept函数时将超时限制(毫秒)作为参数传递即可

例如服务器插座接受(1000);
1秒后自动关闭请求

谢谢,很明显,我甚至没有想到!我在退出循环后调用close()。奇怪的是,docs中没有这个信息:方法没有标记为抛出SocketException。这里只提到调用
close()
可以吗,我的意思是这样做会抛出异常,那么有没有其他方法(不抛出异常,也不基于超时)停止侦听请求?如果连接已被接受,线程正在等待一些数据,该怎么办:while((s=in.readLine())!=null)?@AlexFedulov关闭该套接字以进行输入
readLine()
然后将返回null,并且线程应该已经执行的正常关闭操作将发生。有关要等待x时间然后作出反应的用户,请参阅使用setSoTimeout()。输入和输出流不连接到
ServerSocket
,而是连接到
Socket
,我们说的是关闭
ServerSocket
而不是
Socket
,因此可以在不关闭
Socket
的流的情况下关闭
ServerSocket
。这不起作用。。。如果你让它工作,你能给我一个工作代码的例子吗?这没有意义。。。当您有这样的代码时,socket=serverSocket.accept();这时,阻塞开始了,循环不是我们代码的一部分,所以有办法让阻塞代码查找我设置的标志。。。至少我还没有找到一个方法来做这件事。。。如果你有工作代码,请分享?是的,似乎我遗漏了一个关键的信息,这将使它没有多大意义。在循环重复之前,您需要使accept套接字不阻塞,并且只阻塞一段时间,然后在该区域检查退出标志。如何使accept套接字不阻塞?long on=1L;如果(ioctl(socket,(int)FIONBIO,(char*)&on))@stu这个问题是针对Java的Sockets的。accept()没有参数。