Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to send message to particular websocket connection using java server

I am new to WebSockets.

I have already made a simple server-client chat in WebSockets.

And now I am trying to make client-server-client chat application.

I have a question that in java server how can we send a message to particular WebSocket connection.

If user-A want to send a message to User-B.

Then how can I manage that User-B is using this or that connection or send a message to that particular connection?

I am searching too much for this on google but could not find anything good.

like image 812
manankhh Avatar asked Jun 13 '13 06:06

manankhh


People also ask

How does WebSockets send and receive messages?

WebSockets - Send & Receive Messages. The Message event takes place usually when the server sends some data. Messages sent by the server to the client can include plain text messages, binary data, or images. Whenever data is sent, the onmessage function is fired. This event acts as a client's ear to the server.

What are the default WebSocket encoders in Java?

A WebSocket implementation provides default encoders for Java primitive (int-Integer, long-Long, double-Double etc.) data types. It is possible to write a custom encoder for any of these in order to override the default ones A health check request message. The API does not provide an object corresponding to this message (its a byte buffer)

What are the different types of Java WebSocket messages?

As already stated, the Java WebSocket API supports binary, text, custom Java objects and ping-pong message payloads. These message types can be sent using various styles/modes As you might guess, this leads to a lot of possible permutations and combinations for sending messages (and can be quite confusing at times).

What type of data does WebSockets support?

Web socket protocol supports text and binary data. In terms of Javascript, text refers to as a string, while binary data is represented like ArrayBuffer. Web sockets support only one binary format at a time. The declaration of binary data is done explicitly as follows −


1 Answers

You have to design an architecture for that.

When a client establishes a connection with the server (opens the WebSocket), the server has to keep the connection somewhere (howsoever you're identifying a specific connection with the Java backend you're using), in a data structure that will depend on what you're trying to do. A good identifier would be an ID the user provides (like a nickname that's not already picked by another peer connected to the same server). Otherwise, simply use the socket object as a unique identifier and, when listing other users on the frontend, associate them with their unique identifier so that a client can send a message to a specific peer.

A HashMap would be a good choice for a data structure if a client is going to chat with another specific client, as you can map the unique ID of a client to the socket and find an entry with in O(1) in a hash table.

If you want to broadcast a message from a client to all other clients, although a HashMap would also work pretty well (with something like HashMap.values()), you may use a simple List, sending the incoming message to all connected clients except the original sender.

Of course, you also want to remove a client from the data structure when you lose connection with it, which is easy using a WebSocket (the Java framework you are using should call you back when a socket closes).

Here's an (almost complete) example using a Jetty 9 WebSocket (and JDK 7):

package so.example;
import java.io.IOException;
import java.util.HashMap;

import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;

@WebSocket
public class MyWebSocket {
    private final static HashMap<String, MyWebSocket> sockets = new HashMap<>();
    private Session session;
    private String myUniqueId;

    private String getMyUniqueId() {
        // unique ID from this class' hash code
        return Integer.toHexString(this.hashCode());
    }

    @OnWebSocketConnect
    public void onConnect(Session session) {
        // save session so we can send
        this.session = session;

        // this unique ID
        this.myUniqueId = this.getMyUniqueId();

        // map this unique ID to this connection
        MyWebSocket.sockets.put(this.myUniqueId, this);

        // send its unique ID to the client (JSON)
        this.sendClient(String.format("{\"msg\": \"uniqueId\", \"uniqueId\": \"%s\"}",
                this.myUniqueId));

        // broadcast this new connection (with its unique ID) to all other connected clients
        for (MyWebSocket dstSocket : MyWebSocket.sockets.values()) {
            if (dstSocket == this) {
                // skip me
                continue;
            }
            dstSocket.sendClient(String.format("{\"msg\": \"newClient\", \"newClientId\": \"%s\"}",
                    this.myUniqueId));
        }
    }

    @OnWebSocketMessage
    public void onMsg(String msg) {
        /*
         * process message here with whatever JSON library or protocol you like
         * to get the destination unique ID from the client and the actual message
         * to be sent (not shown). also, make sure to escape the message string
         * for further JSON inclusion. 
         */
        String destUniqueId = ...;
        String escapedMessage = ...;

        // is the destination client connected?
        if (!MyWebSocket.sockets.containsKey(destUniqueId)) {
            this.sendError(String.format("destination client %s does not exist", destUniqueId));
            return;
        }

        // send message to destination client
        this.sendClient(String.format("{\"msg\": \"message\", \"destId\": \"%s\", \"message\": \"%s\"}",
                destUniqueId, escapedMessage));
    }

    @OnWebSocketClose
    public void onClose(Session session, int statusCode, String reason) {
        if (MyWebSocket.sockets.containsKey(this.myUniqueId)) {
            // remove connection
            MyWebSocket.sockets.remove(this.myUniqueId);

            // broadcast this lost connection to all other connected clients
            for (MyWebSocket dstSocket : MyWebSocket.sockets.values()) {
                if (dstSocket == this) {
                    // skip me
                    continue;
                }
                dstSocket.sendClient(String.format("{\"msg\": \"lostClient\", \"lostClientId\": \"%s\"}",
                        this.myUniqueId));
            }
        }
    }

    private void sendClient(String str) {
        try {
            this.session.getRemote().sendString(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sendError(String err) {
        this.sendClient(String.format("{\"msg\": \"error\", \"error\": \"%s\"}", err));
    }
}

The code is self explanatory. About JSON formatting and parsing, Jetty has some interesting utilities within package org.eclipse.jetty.util.ajax.

Also note that if your WebSocket server framework is not thread-safe, you will need to synchronize the data structure to make sure there's no data corruption (here MyWebSocket.sockets).

like image 194
eepp Avatar answered Oct 23 '22 17:10

eepp