2013-05-27 4 views
1

웹 서버를 서버 측에서 사용하고 있습니다. 나는 응용 프로그램에서 서버로 연결하고 열려있는 모든 연결에 메시지/알림을 보낼 수있었습니다. 원하는 것은 무엇입니까웹 소켓 연결 서버 측 관리

- 사용자가 메시지/알림을 특정 사용자에게 보낼 수 있도록 연결 (예 : 열린 웹 소켓)을 인식하는 방법 사용자 (웹 소켓을 통해). 여기 내 코드가 먼저 데스크톱 클라이언트 측 코드입니다.

if(e.getSource() == connect) { 
     try { 
      cc = new WebSocketClient(new URI("http://localhost:8080/webSocket/chatServlet"), (Draft) draft.getSelectedItem()) { 
       @Override 
       public void onMessage(String message) { 
        ta.append("got: " + message + "\n"); 
        ta.setCaretPosition(ta.getDocument().getLength()); 
       } 
       @Override 
       public void onOpen(ServerHandshake handshake) { 
        ta.append("You are connected to ChatServer: " + getURI() + "\n"); 
        ta.setCaretPosition(ta.getDocument().getLength()); 
       } 

       @Override 
       public void onClose(int code, String reason, boolean wasClean) { 
        ta.append("You have been disconnected from: " + getURI() + "; Code: " + code + " " + reason + "\n"); 
        System.out.println("the reason for disconnection is ........ "+wasClean); 
              ta.setCaretPosition(ta.getDocument().getLength()); 
        connect.setEnabled(true); 
        uriField.setEditable(true); 
        draft.setEditable(true); 
        close.setEnabled(false); 
       } 

       @Override 
       public void onError(Exception ex) { 
        ta.append("Exception occured ...\n" + ex + "\n"); 
        ta.setCaretPosition(ta.getDocument().getLength()); 
        ex.printStackTrace(); 
        connect.setEnabled(true); 
        uriField.setEditable(true); 
        draft.setEditable(true); 
        close.setEnabled(false); 
       } 
      }; 

      close.setEnabled(true); 
      connect.setEnabled(false); 
      uriField.setEditable(false); 
      draft.setEditable(false); 
      cc.connect(); 
     } catch (URISyntaxException ex) { 
      ta.append(uriField.getText() + " is not a valid WebSocket URI\n"); 
     } 
    } else if(e.getSource() == close) { 
     cc.close(); 
    } 
} 

지금 여기

public class SocketListener extends WebSocketServlet { 

/** 
* 
*/ 
private static final long serialVersionUID = 1L; 
private static ArrayList<MyStreamBound> mmiList = new ArrayList<MyStreamBound>(); 
private HttpServletRequest request; 
private String clientName; 
private String zone; 
private String subId; 
@Override 
protected StreamInbound createWebSocketInbound(String protocol) { 
    System.out.println("protocol values are..."+protocol); 
    return new MyStreamBound(); 

} 



private class MyStreamBound extends StreamInbound{ 
    WsOutbound myoutbound; 


    public MyStreamBound(){ 
     super(); 

    } 
    @Override 
    public void onOpen(WsOutbound outbound){ 
     try { 


      System.out.println("Open Client."+outbound.toString()+" and value of this "+this.toString()); 
      this.myoutbound = outbound; 
      mmiList.add(this); 
      outbound.writeTextMessage(CharBuffer.wrap("Hello!")); 

     } catch (IOException e) { 
     e.printStackTrace(); 
     } 
    } 


    @Override 
    protected void onBinaryData(InputStream arg0) throws IOException { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    protected void onTextData(Reader recievedData) throws IOException { 
     BufferedReader in = new BufferedReader(recievedData); 
     String line = null; 
     StringBuilder rslt = new StringBuilder(); 
     while ((line = in.readLine()) != null) { 
      rslt.append(line); 
     } 
     System.out.println(rslt.toString()); 

     for(MyStreamBound mmib: mmiList){ 
      CharBuffer buffer = CharBuffer.wrap(rslt.toString()); 
      mmib.myoutbound.writeTextMessage(buffer); 
      mmib.myoutbound.flush(); 

     } 

    } 

    @Override 
    protected void onClose(int status){ 
     System.out.println("Close Client."+status); 
     mmiList.remove(this); 
    } 


} 

}

답변

1

나는 최근에 같은 질문에왔다 ... 서버 측 코드입니다. 각 객체의 내부 당신의 mmib에 대한 고유 ID를 가질 수 있도록

당신은 몇 가지 옵션이 있습니다

...

  1. 는 생성자에서 세션 ID를 받고 당신의 MyStreamBound을 만듭니다. 아마 이전에 연결

    protected StreamInbound createWebSocketInbound(String protocol, HttpServletRequest req) { 
        System.out.println("protocol values are..."+protocol); 
        return new MyStreamBound(req.getSession().getId()); 
    } 
    
  2. 더 안전하게 만들 수 있습니다. 연결하면 첫 번째 메시지를 사용자에 대한 정보를 보내는 핸드 셰이크로 보냅니다. 이 정보를 MyStreamBound 객체 인스턴스의 필드로 저장할 수 있습니다.

두 경우 모두 필요에 따라 for 문에서이 값의 유효성을 검사 할 수 있습니다. 귀하의 질문에서 별도로

이, 추천, 나는 당신이 사용하는 구문에 문제가 있었다 : 여러 동시 액세스가있는 경우,

for(MyStreamBound mmib: mmiList){ 
     CharBuffer buffer = CharBuffer.wrap(rslt.toString()); 
     mmib.myoutbound.writeTextMessage(buffer); 
     mmib.myoutbound.flush(); 

    } 

그것은 mmiList에서 Iterator를 생성하고 (즉, 웹 소켓을위한 기능) , 예외가 발생합니다.

for(int i = 0; i < mmiList.size(); i++) { 
     MyStreamBound mmib = mmiList.get(i); 
     CharBuffer buffer = CharBuffer.wrap(rslt.toString()); 
     mmib.myoutbound.writeTextMessage(buffer); 
     mmib.myoutbound.flush(); 

    } 

당신이 컬렉션을 만드는 장난하지 않는이 방법과 코드 스레드를 만들 : 나는 (이 그 좋은 보이지 않는 경우에도) 이런 식으로 썼다. 사실, 조금 실망했지만, for 루프가 Java에서 작동하는 방식입니다.

일반적인 for 루프는 그렇게 효율적이지 않습니다. 나는 왜 mmiList가 Threadsafe Collection이 아닌지 이해하지 못한다. 당신은 보통의 for 루프를 사용하지 않으려는 경우에도 Thread-safe iteration over a collection과 같은 대안을 확인할 수 있습니다.

+0

좋은 제안에 감사드립니다. 난 특별히 ArrayList 포인트에 초점을 맞 춥니 다. 이제는 CopyOnArrayList를 사용하고 있습니다. –

+1

당신은 환영합니다. 다른 부분도 도움이 되었기를 바란다. 서비스가 많은 사용자를 다루는 경우 실수로 큰 성능 문제가 발생할 수 있으므로이 부분에 매우주의해야한다. – Martin