2017-12-21 9 views
1

내 제목은 아마도 가장 설명 적이 지 않지만 가능한 한 많은 코드를 표시하여 모든 사람들이 내 질문을 더 잘 이해할 수 있도록 노력하겠습니다. 내 프로젝트의 클라이언트 측에서 서버에 정보를 쿼리하는 방법은 다음과 같습니다.다른 요청을 차단하지 않고 소켓 입력을 청취하는 방법

private String GENERATEGROUPKEY() 
{ 
    /* `out` is a PrintWriter using the sockets output stream */ 
    out.println("GENERATEGROUPKEY"); 

    try 
    { 
     /* `in` is a BufferedReader using the sockets input stream */ 
     String response = in.readLine(); 
     String[] temp = response.split(" "); 

     return temp[1]; 
    } 
    catch (IOException ex) 
    { 
     return null; // throw connection error to client 
    } 
} 

내 문제는 언제든지, 서버 정보와 같은 소켓을 통해 클라이언트에 원치 않는 메시지를 보낼 수 있다는 것입니다 (채팅 클라이언트가 수신처럼 생각 : 이것은 일반적인 요청의 예입니다 메시지). 저의 실패한 아이디어는 우리가 다른 쿼리의 중간에 있지 않는 한 그러한 메시지를 수신하는 스레드를 만드는 것이 었습니다.하지만 그 스레드를 방해하더라도 메시지를 계속해서 보내야하기 때문에 실패했습니다. 클라이언트 쿼리로 이동했습니다. 여기

private String GENERATEGROUPKEY() 
{ 
    out.println("GENERATEGROUPKEY"); 
    listenThread.interrupt(); // block listenThread from recieving response 

    try 
    { 
     String response = in.readLine(); 
     String[] temp = response.split(" "); 

     listenThread = new PulseThread(in); // we're done, so allow 
     listenThread.start(); 
     return temp[1]; 
    } 
    catch (IOException ex) 
    { 
     listenThread = new PulseThread(in); // we're done, so allow 
     listenThread.start(); 
     return null; // throw connection error to client 
    } 
} 

listenThread

public class PulseThread extends Thread 
{ 
    private BufferedReader in; 

    public PulseThread(BufferedReader in) 
    { 
     this.in = in; 
    } 

    @Override 
    public void run() 
    { 
     while (true) 
     { 
      if (Thread.currentThread().isInterrupted()) 
      { 
       break; 
      } 
      try 
      { 
       String line = in.readLine(); 
       System.out.println(line); 
       String[] params = line.split(" "); 
       if (params[0].equals("PULSED")) 
       { 
        NotificationManager.sendNotification("You have been pulsed!", "Pulsed by: " + params[1]); 
       } 
      } 
      catch (Exception ex) 
      { 

      } 
     } 
    } 
} 

내가 BufferedReader의 중간에 스레드를 중단 '나는하지 않는 readLine()와의 차단 호출하면 바로 차단 호출을 취소 할 것'이라는 인상을 이전했다 정확히 무엇 다른 일을 잘못하고있어.

도움을 주시면 감사하겠습니다.

편집 : 그래서이 문장 위에 단지 몇 줄 내 가정을 찾고 스레드를 방해하지 않는 것 같습니다 readLine() 취소합니다. 나는 인터럽트 스레드 아이디어가 없다고 생각합니다. 이 작업을 수행하는 올바른 방법은 무엇입니까?

+0

함께, 오류 : [태그 : 멀티 스레딩]? 그리고 스레드가 인터럽트되면 I/O 작업이 취소 될 것입니다. – EJP

+0

@EJP이 질문은 다중 스레드 질문이 아닙니까?합법적이고 고유 한 질문에 대한 -1이 적절한 지 확실하지 않지만 나는 빗나갑니다. Javadocs는 "인터럽트 가능 채널에서이 스레드가 I/O 작업에서 차단되면 채널이 닫힙니다."라고 말합니다. 이것은 나에게 적용되지 않습니까? 만약 내가해야 할 일을 모르고 있기 때문에 나는 가능한 해결책이 될 수 없다. – Headline

+0

@Headline 실제 클래스에는 Java 클래스와 마찬가지로 [InterruptibleChannel] (https://docs.oracle.com/javase/8/docs/api/java/nio/channels/InterruptibleChannel.html)이 있습니다. BufferedReader *는 예외를 던질 수도 있지만 아무 것도하지 않으면 알 수 없습니다. – matt

답변

2

여기서 일반적인 패턴은 소켓에서 하나의 스레드 처리 출력 (대기 중에 차단)을 수행 한 다음 메시지를 요청한 올바른 메시지로 발송한다는 것입니다.

내가 좋아하고 여러 프로젝트에서 성공적으로 사용한 한 가지 구현은 일반 헤더 (메시지 유형 포함)의 일부로 임의로 생성 된 ID를 "요청"에 추가하고 서버가 항상 ID를 미러링하도록하는 것입니다 이 응답은 클라이언트가 어떤 유형의 메시지인지 신경 쓰지 않고 요청을 응답과 연관시킬 수있게합니다.

구체적으로는 클래스 (예 : sendRequest(type, body, callback)registerUnsolicitedHandler(type, callback))와 같은 클래스입니다.

sendRequesttype과 임의로 생성 된 ID로 메시지 헤더를 작성하고 콜백 함수에 대한 참조와 함께 보류중인 응답 목록에 추가 한 다음 완료된 메시지를 서버에 보냅니다.

registerUnsolicitedHandler 이름에서 알 수 있듯이 들어오는 메시지에 ID가없는 경우 사용할 메시지 유형 맵에 콜백 함수를 추가합니다.

들어오는 메시지를 처리하는 별도의 스레드에서 메시지가 ID를 가지고 있으면 보류중인 응답 목록을 검색하고 메시지 본문과 함께 적절한 콜백을 호출하는 경우 들어오는 데이터를 deserialise하여 헤더에서 형식과 ID를 얻습니다 주 스레드에서 잠금과 같은 세부 사항에 대해 설명하고 있습니다. 그렇지 않으면 지정된 유형의 요청하지 않은 핸들러 목록을 검색하고 해당 콜백을 호출합니다.