2017-01-24 1 views
1

stopServer() 서버에서 Mac, Linux 및 UNIX 컴퓨터에서 완벽하게 작동하지만 Windows에서 닫으려고하면 최소 1 초가 소요됩니다. 각각ServerSocket의 제한 시간으로 인해 소켓이 닫히도록합니다. Thread.join()에 전화 할 때마다 한 번에 하나씩 반대로 Linux, Mac 등에서 모든 작업을 한꺼번에 닫을 수 있기를 바랍니다.스레드가 Windows에서 Thread.join()까지 중지되지 않음

서버 코드

public class FileServer { 

    private ArrayList<Thread> sockets = new ArrayList<>(); 
    private ServerSocket fileServer; 

    public void startServer(int port, int maxThreads, int timeout) throws IOException { 

     fileServer = new ServerSocket(); 
     fileServer.setPerformancePreferences(1, 0, 1); 
     fileServer.bind(new InetSocketAddress(port)); 

     for (int threads = 0; threads < maxThreads; threads++) { 
      sockets.add(new Thread(new ServerInit(fileServer, timeout))); 
      System.out.println("Socket " + threads + " initialized..."); 
     } 

     for (int socket = 0; socket < sockets.size(); socket++) { 
      (sockets.get(socket)).start(); 
      System.out.println("Socket " + socket + " started!"); 
     } 
    } 

    public void stopServer() { 
     if (fileServer.isBound()) { 
      for (int thread = 0; thread < sockets.size(); thread++) { 
       sockets.get(thread).interrupt(); 
      } 
      for (int thread = 0; thread < sockets.size(); thread++) { 
       try { 
        if (sockets.get(thread).isAlive()) { 
         sockets.get(thread).join(); 
        } 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 
} 

class ServerInit implements Runnable { 
    private ServerSocket server; 
    private int timeout; 

    public ServerInit(ServerSocket server, int timeout) { 
     this.server = server; 
     this.timeout = timeout; 
    } 

    public void run() { 
     while (!Thread.interrupted()) { 
      try { 
       server.setSoTimeout(1000); 
       Socket client = server.accept(); 
       client.setSoTimeout(timeout); 
       processRequest(receiveRequest(client), client); 
       client.close(); 
      } catch (SocketTimeoutException ste) { 
      } catch (IOException io) { 
       io.printStackTrace(); 
      } 
     } 
     System.out.println("Socket closed"); 
    } 
} 

왜 그들이 while 루프를 종료하기 전에 그들과 합류하기 위해 저를 을 필요로하는 스레드가되어 있습니까? 테스트를 마쳤으며 모든 스레드가 시작되고 모든 스레드가 제대로 인터럽트되었는지 확인합니다.

또한 System.out.println()while 루프에 넣으면 하나의 스레드 만 제대로 인쇄됩니다.

편집

나는 타임 아웃 시간 accept 기다려야한다는 것을 인식보다 훨씬 더 많은입니다. 즉, 1 초의 제한 시간입니다. 이 모든 작품 다른 플랫폼에서 완벽하게 작동합니다. 나는 모든 스레드를 중단하고 실제로 스레드가 멈추는 지 확인하기 위해 스레드에 합류합니다. 가장 큰 관심사는 이러한 스레드가 있어야 할 때 동시에 시간 초과되지 않는 이유입니다.

+0

정확히 어떻게 상상하고 있습니까? 쓰레드가'accept'에 있고, 쓰레드가 중단됩니다. InterruptedException이 발생했다고 생각합니까? 규칙 상으로는 검사중인 모든 인터럽트 플래그가 지워집니다. –

+0

Javadoc에는'ServerSocket.accept()'가 인터럽트 가능한 것이 없으므로 스레드는 모두 accept timeout을 기다리고 있습니다. 코드가 의도 한대로 작동합니다. 흥미로운 점은 일부 플랫폼에서는 더 빠르지 만 Windows에서 작동하는 방식에는 아무런 문제가 없다는 것입니다. 제목이 의미가 없습니다. – EJP

+0

인터럽트 플래그를 검사하는 대신 스레드를 멈추기 위해'ServerInit' 클래스의 while 루프에서 휘발성 정적 변수 (세마포어)를 사용하지 않으시겠습니까? –

답변

2

* nix 운영 체제의 경우 소켓 구현은 도중의 어느 곳에서나 accept에 고정되지 않습니다. Windows의 경우

PlainSocketImpl 클래스 defines accept as synchronized :

protected synchronized void accept(SocketImpl s) throws IOException { 
    // ... 
} 

무엇 발생하는 accept은 한 번에 하나 개의 스레드에 의해 실행되고 있다는 점이다. 1 초 제한 시간은 잠금이 최종적으로 획득 된 후 기본 accept에 의해서만 고려됩니다.

이것이 의도적인지 알 수 없지만 Java 메일 목록에 문의해야합니다.

관련 문제