내 주요 스레드에는 ServerSocket 객체 while(listening)
를 호출 accept()
한 다음 새 클라이언트 스레드를 시작하고 새 클라이언트가 수락 될 때 컬렉션에 추가 하는 루프 가 있습니다.
또한 ‘exit’과 같은 명령을 실행하는 데 사용하려는 Admin 스레드가 있는데, 이는 모든 클라이언트 스레드를 종료하고 자체 종료하며 주 스레드를 false로 설정하여 종료시킵니다.
그러나 루프 블록 의 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();
}
}
이 메소드를 호출하여 예외없이 어디서나 모든 소켓을 닫을 수 있습니다.
답변
답변
좋아, 나는 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.
*/
}
실제 예 :
이 예에서는 ServerSocket이 스레드 내부의 연결을 기다리고 있습니다. 앱을 닫을 때 앱을 닫기 전에 스레드 (보다 구체적으로 소켓)를 깔끔하게 종료하고 싶습니다. 그래서 ServerSocket에서 .setSoTimeout ()을 사용하고 throw 된 인터럽트를 사용합니다 시간 초과 후 부모가 스레드를 종료하려고하는지 확인하고 확인하십시오. 그렇다면 소켓을 닫은 다음 스레드가 완료되었음을 나타내는 플래그를 설정 한 다음 스레드 루프를 종료하여 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;
}
};
}
그런 다음 내 컨트롤러 클래스에서 … (필요에 따라 관련 코드 만 표시하고 자신의 코드로 마사지합니다)
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());
});
}
}
나는 이것이 길 아래 누군가를 돕기를 바랍니다.