ServerSocket accept () 메소드를 어떻게 중단 할 수 있습니까?
내 주요 스레드에는 ServerSocket 객체 while(listening)
를 호출 accept()
한 다음 새 클라이언트 스레드를 시작하고 새 클라이언트가 수락되면 컬렉션에 추가 하는 루프 가 있습니다.
또한 'exit'과 같은 명령을 실행하는 데 사용하려는 Admin 스레드가 있는데, 이는 모든 클라이언트 스레드를 종료하고 자체 종료하며 주 스레드를 거짓으로 들려서 종료시킵니다.
그러나 루프 블록 의 accept()
호출은 while(listening)
중단 할 수있는 방법이 없어서 while 조건을 다시 확인할 수없고 프로그램을 종료 할 수 없습니다!
더 좋은 방법이 있습니까? 또는 차단 방법을 방해하는 방법은 무엇입니까?
당신은 호출 할 수있는 close()
다른 스레드에서, 그리고 accept()
호출이 발생합니다 SocketException
.
시간 초과를 설정 accept()
하면 지정된 시간이 지나면 통화가 차단 시간을 초과합니다.
http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT
차단
Socket
작업에 시간 초과를 설정하십시오 .ServerSocket.accept(); SocketInputStream.read(); DatagramSocket.receive();
차단 작업을 시작하기 전에 옵션을 설정해야 적용됩니다. 시간 초과가 만료되고 작업이 계속 차단되면
java.io.InterruptedIOException
발생합니다. 은Socket
이 경우에 폐쇄되지 않는다.
호출되어 close()
온 ServerSocket
옵션?
http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29
이 소켓을 닫습니다. accept ()에서 현재 차단 된 스레드는 SocketException을 발생시킵니다.
당신은 break serverocket.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) {
}
}
예외 가 발생 하는 이유 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();
}
}
이 메소드를 호출하여 예외없이 어디서나 모든 소켓을 닫을 수 있습니다.
serverSocket.setSoTimeout (timeoutInMillis)를 사용하십시오 .
좋아, 나는 OP의 질문을보다 직접적으로 다루는 방식으로 이것을 작동시켰다.
내가 이것을 어떻게 사용하는지에 대한 Thread 예제에 대한 짧은 대답을 계속 읽으십시오.
짧은 답변:
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.
*/
}
실제 예 :
In this example, I have a ServerSocket waiting for a connection inside a Thread. When I close the app, I want to shut down the thread (more specifically, the socket) in a clean manner before I let the app close, so I use the .setSoTimeout() on the ServerSocket then I use the interrupt that is thrown after the timeout to check and see if the parent is trying to shut down the thread. If so, then I set close the socket, then set a flag indicating that the thread is done, then I break out of the Threads loop which returns a null.
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;
}
};
}
Then, in my Controller class ... (I will only show relevant code, massage it into your own code as needed)
public class Controller {
Server server = null;
private static final int port = 10000;
private void stopTheServer() {
server.stopServer();
while (server.isRunning() {
//We just wait for the server service to stop.
}
}
@FXML private void initialize() {
Platform.runLater(()-> {
server = new Server(port);
server.startServer();
Stage stage = (Stage) serverStatusLabel.getScene().getWindow();
stage.setOnCloseRequest(event->stopTheServer());
});
}
}
I hope this helps someone down the road.
Another thing you can try which is cleaner, is to check a flag in the accept loop, and then when your admin thread wants to kill the thread blocking on the accept, set the flag (make it thread safe) and then make a client socket connection to the listening socket. The accept will stop blocking and return the new socket. You can work out some simple protocol thing telling the listening thread to exit the thread cleanly. And then close the socket on the client side. No exceptions, much cleaner.
참고URL : https://stackoverflow.com/questions/2983835/how-can-i-interrupt-a-serversocket-accept-method
'Programming' 카테고리의 다른 글
내 보낸 서비스에는 권한이 필요하지 않습니다. 무엇을 의미합니까? (0) | 2020.06.24 |
---|---|
불필요한 svn : mergeinfo 속성 제거 (0) | 2020.06.24 |
쉘 변수를 따옴표로 묶을 때? (0) | 2020.06.24 |
F # 시작하기 (0) | 2020.06.24 |
그래프 API를 사용하여 주식 수를 얻는 방법 (0) | 2020.06.23 |