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()没有参数。