Haseeb Wali
Haseeb Wali

Reputation: 1171

web Sockets connection Managment on Server Side

I am using web sockets on the server side. I managed to make connection from application to the server and send message/notification to every open connection.What i want is

-how to recognize the connection(i.e opened websocket) so that user can send message/notification to a specific user(via webSockets). Here is my code first the desktop client side code is.

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

Now here is server side code...

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


}

}

Upvotes: 1

Views: 232

Answers (1)

Martin
Martin

Reputation: 3058

I have recently come to the same question.

You have some options...

  1. Create your MyStreamBound getting SessionID in the constructor, so you have an unique ID for each object insider your mmib.

    protected StreamInbound createWebSocketInbound(String protocol, HttpServletRequest req) {
        System.out.println("protocol values are..."+protocol);
        return new MyStreamBound(req.getSession().getId());
    }
    
  2. Maybe connected to the previous to make it more secure. When you connect, send a first message as a handshake where you send info about the user. You can store this information as fields in your MyStreamBound Object instance.

For both cases, you can then validate this value inside your for statement as needed.

Apart from your question, as a recommendation, I had trouble with this syntax you use:

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

     }

It generates an Iterator from mmiList and, if you have multiple concurrent accesses (that's what WebSocket is for), it will cause an exception. I wrote it this way (even if it doesn't seem that nice):

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

     }

This way you're not messing with creating Collections and make the code Threadsafe. As a matter of fact, I'm a little disappointed by this, but it's how the enhanced for loop works in Java.

The normal for loop is not that efficient. I don't understand why the mmiList is not a Threadsafe Collection, it doesn't make any sense. You could check these alternatives as well: Thread-safe iteration over a collection if you don't want to use the normal for loop.

Upvotes: 1

Related Questions