1

我在服务器端使用网络套接字。我设法从应用程序连接到服务器并向每个打开的连接发送消息/通知。我想要的是

-如何识别连接(即打开的 websocket),以便用户可以向特定用户发送消息/通知(通过 webSockets)。这是我的代码,首先是桌面客户端代码。

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


}

}

4

1 回答 1

1

我最近遇到了同样的问题。

你有一些选择...

  1. 在构造函数中创建获取 SessionID 的 MyStreamBound,这样您的 mmib 内部的每个对象都有一个唯一的 ID。

    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 ,如果您有多个并发访问(这就是 WebSocket 的用途),它将导致异常。我是这样写的(即使看起来不太好):

    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 不是线程安全集合,它没有任何意义。您也可以检查这些替代方案:如果您不想使用正常的 for 循环,则对集合进行线程安全迭代。

于 2013-05-31T08:49:30.987 回答