[java] ServerSocket accept () 메소드를 어떻게 중단 할 수 있습니까?

내 주요 스레드에는 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()
해당 소켓에 또는 연결되어 있기 때문 입니다. 먼저 입력 및 출력 스트림을 닫아이 예외를 피할 수 있습니다. 그런 다음를 닫습니다 . 예를 들면 다음과 같습니다.outputstreaminputstreamServerSocket

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());
        });
    }

}

나는 이것이 길 아래 누군가를 돕기를 바랍니다.