2011-09-13 6 views
3

StackOverflow와 Google을 둘러 보았고 문제에 대한 해결책을 찾을 수 없었으므로 여기에 제가하고있는 일이 있습니다.어떻게 프로그래밍 방식으로 InputStream에서 읽기를 취소 할 수 있습니까?

콘솔 응용 프로그램 용 서버가 있으며 사용자는 모든 텔넷 클라이언트와 연결됩니다. 세 개의 개별 스레드를 가진 클라이언트를 처리하고 있습니다. 하나의 스레드 (ClientThread)가 클라이언트에 대한 모든 프로그램 액세스를 제어하고, ClientThread는 입력을 처리하고 출력을 전송하는 두 개의 스레드를 유지합니다. ClienThread는 클라이언트 소켓을 읽고 입력을 처리하는 ProcessingThread에 입력 (있는 경우)을 보내고 사용자가 지시 한 작업을 수행합니다. 출력 스레드는 보낼 필요가있는 출력 대기열을 관리하고 대기 상태가 될 때마다 전송합니다. 사용자가 연결을 끊을 때 때때로 출력 대기열이 비어있을 때까지 연결이 유지되도록 연결을 설정하기 위해 연결이 종료되기 전에 Output "queue"에 남아있는 Output을 사용합니다. 그러나 소켓을 읽는 스레드 (그리고 더 이상 출력이 없을 때 궁극적으로 그것을 닫습니다.) 읽기에 걸려 있고 닫을 수 없습니다. 사용자가 연결을 끊을 때 소켓을 닫을 때까지는 문제가되지 않았습니다. 관련 코드를 알려 드리겠습니다.

public class ClientThread extends Thread { 
    // Initialization and other code not pertaining to the problem 

    public void run() { 
     while (connected) { 
     try { 
      String input = in.readLine(); 

      if (input != null) { 
       processor.queue(TextUtility.processBackspaceChars(input)); 
       timeoutTimer.interrupt(); 
      } 
     } catch (Exception e) { 
      if (e.getMessage() != null && !(e.getMessage().equals("socket closed"))) 
       server.appendError("Issue reading from client: " 
        + getClientDisplayInfo() + "\n" 
        + "&r-The issue is:&w- " + e.getMessage() + "&r-."); 
     } 
     } 

     while (disconnecting) { 
     try { 
      if (outputThread.hasOutput()) { 
       sleep(10); 

      } else { 
       disconnecting = false; 
       outputThread.disconnect(); 
       client.close(); 
      } 
     } catch (Exception exc) { 
      server.appendError("Failed to close the Thread for client: " + getClientDisplayInfo()); 
     } 
     } 
    } 

    public void disconnect() { 
     try { 
     connected = false; 
     disconnecting = true; 
     processor.disconnect(); 
     timeoutTimer.disconnect(); 
     in.close(); // This is the BufferedReader that reads the Socket Input Stream 
     this.interrupt(); // This was my attempt to break out of the read, but it failed 

     } catch (Exception e) { 
     server.appendError("Failed to close the Thread for client: " 
       + getClientDisplayInfo()); 
     } 
    } 
} 

출력을 계속 보내야하므로 소켓을 닫지 않고 읽음을 취소 할 수 있습니다.

+0

Stacker의 응답이 완벽하게 작동하는 동안 가져온 것처럼 여러 클라이언트에서 확장되지 않았습니다. 나는이 프로그램이 많은 수의 고객들을 지원할 것임을 의심 스럽다. 가능한 한 효율적으로 만들려고 시도하고있다. 마침내 해결 된 솔루션은 OutputThread에 'disconnect'알림이 전송되면 플래그가 변경되고 출력 큐에 대기열이 있으면 소켓을 닫으라는 클라이언트에 알리는 것입니다. 이렇게하면 출력 대기열을 지우는 데 몇 초가 더 오래 걸리는 모든 작업이 동일하게 유지됩니다. –

답변

4

내가 직면 한 문제와 비슷합니다. yesterday 입력 스트림에서 is.available()을 호출하고 (차단) 읽기를 수행하기 전에 데이터를 사용할 수 있는지 확인할 수 있습니다.

+0

감사합니다. 이것은 매력처럼 작동했습니다. 내가 이것을 게시 한 후에 OutputThread에 플래그를 추가하여 클라이언트가 소켓이 비었을 때 소켓을 닫도록 지시 할 수 있음을 알았습니다. 하지만 당신의 방법은 완벽하게 작동합니다. Google/StackOverflow 외에 소켓에 ​​대한 API를 참조해야한다고 생각합니다. –

+0

이것은 새로운 데이터에 대한 스트림의 연속 폴링을 포함합니다. 이는 소수의 고객에게만 적용됩니다. 이것은 전혀 확장되지 않습니다. 일반적으로이 작업을 수행하지는 않겠지 만 작고로드가 적은 프로그램의 경우이 작업이 가능합니다. – Jay

3

사용할 수 없음()을 호출하지 마십시오. 너무 자주 호출하는 CPU를 낭비하거나 너무 자주 호출하지 않아도 응답 시간이 오래 걸릴 수 있습니다. Socket에서 읽기 타임 아웃을 설정하고 리더 스레드가 이동 할 때마다 'cancel'플래그를 확인하도록하십시오. 당신이 그것을 설정하고 싶을 때부터 플래그를 설정하십시오.

관련 문제