A few days ago I made a website: modubox.cn, which has a group chat plug-in, many people asked how to achieve it. Briefly, in order to quickly complete the group chat function, I chose to start with the simplest WebSocket.

What is WebSocket?

If you want to use it, you need to know about it. WebSocket is also a network protocol based on TCP. The biggest difference between WebSocket and HTTP is that it is a two-way communication protocol. After a connection is established, both the WebSocket server and client can actively send or receive data to each other, while HTTP can only actively initiate communication with the client.

So WebSocket can be used for chat, of course other places can also be used, if you do customer service system or push messages can start from here.

How to achieve single chat/group chat?

Group chat: All clients send messages to the server, and the server sends messages to all clients.

Single chat: WebSocket clients cannot communicate with each other directly. If they want to communicate, they must be forwarded by the server.

Group chat chat

implementation

1. Introduce WebSocket support

We built our project using the most popular Spring Boot framework and then introduced Spring Boot support for WebSocket:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
Copy the code

2. Open the WebSocket

@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }}Copy the code

3. The service side

There are mainly the following points:

  1. Declare the service endpoint path

  2. Store all connected users and wait for matching users

  3. Connect onOpen, message OnMessage, close onClose, error onError method

  4. Send a message to a particular connector

    @serverendpoint (value = “/websocket/random/”) @Component Public class ChatRandomServer {// All connections public static ConcurrentHashMap<String, ChatRandomServer> webSocketSet = new ConcurrentHashMap<>(); // A Session is used to connect to a client and send data to the client. Private static List webSocketLiveList = new CopyOnWriteArrayList(); Private String ID = “”; // Connection object ID private String toUser = “”;

    / * * * connection is established successfully the method called * / @ OnOpen public void OnOpen (Session Session) {Session. SetMaxIdleTimeout (3600000); this.session = session; String IP = iputil. getRemoteAddress(session); this.id = ip; ChatRandomServer put = webSocketSet.put(this.id, this); If (put == null) {try {if (pair()) {sendMessage(" match successful "); } } catch (IOException e) { e.printStackTrace(); }} else {try {sendMessage(" match failed "); webSocketSet.remove(this.id); session.close(); } catch (IOException e) { e.printStackTrace(); }} log.info(" User {} join! {}", this.id, webSocketSet.size()); } @onClose public void OnClose () {ChatRandomServer UserId = webSocketSet.get(toUser); webSocketLiveList.remove(this.id); if (UserId ! = null) {try {sendToUser(session, "the other party has left ", toUser); } catch (IOException e) { e.printStackTrace(); } } webSocketSet.remove(this.id); Log.info ("{} Connection closed! The current online number: {}, the current in the number of matching: {} ", enclosing id, webSocketSet. The size (), webSocketLiveList. The size ()); } /** * @param message public void OnMessage (String message, Session Session) {log.info(" Message from {} : {}", this.id, message); try { ChatRandomServer.sendToUser(session, message, toUser, 2); } catch (IOException e) { e.printStackTrace(); }} @onError public void OnError (Session Session, Throwable error) {log.error(" error "); error.printStackTrace(); Try {SendSelf(session," server error "); } catch (IOException e) { e.printStackTrace(); Throws IOException {SendSelf(this.session, message);}} /** * send a message to yourself */ public void sendMessage(String message) throws IOException {SendSelf(this.session, message); } private static void SendSelf(Session session, String message) throws IOException { session.getBasicRemote().sendText(message); } public static void sendToUser(Session Session, String message, String sendUserId) throws IOException { ChatRandomServer UserId = webSocketSet.get(sendUserId); if (UserId ! = null) { UserId.sendMessage(message); } else {SendSelf(session, "send failed "); Private void sendOnlineCount(String message) {for (String key: webSocketSet.keySet()) { try { if (key.equals(id)) { continue; } webSocketSet.get(key).sendMessage(message); } catch (IOException e) { e.printStackTrace(); Public void sendToAll(String message) throws IOException {for (String key: webSocketSet.keySet()) { try { webSocketSet.get(key).sendMessage(message); } catch (IOException e) { e.printStackTrace(); }}} public synchronized Boolean pair() throws IOException {// If (webSocketlivelist.size () > 0) {// Match one user randomly  Random ra = new Random(); int nextInt = ra.nextInt(webSocketLiveList.size()); toUser = webSocketLiveList.get(nextInt); try { ChatRandomServer UserId = webSocketSet.get(toUser); UserId.setToUser(id); SendToUser (session, "Pairing succeeded ", toUser); } catch (IOException e) { e.printStackTrace(); } webSocketLiveList.remove(nextInt); return true; } webSocketlivelist.add (id); return false; }Copy the code

    }

4. Front-end support

start: Function () {if (typeof (WebSocket) === "undefined") {alert(" your browser does not support sockets ")} else {// Instantiate socket this.socket = new WebSocket(`ws://localhost:8082/websocket/room`); This.socket. onopen = this.open // Listen for socket errors this.socket. onError = this.error // Listen for socket messages this.socket.onmessage = this.getMessage this.socket.onclose = this.close } }, open: function () { }, error: Function () {}, getMessage: function (obj) {let data = json.parse (obj); if (data.code === 1) { } else if (data.code === 2) { } else { } }, close: function (e) { }, doSend: function () { if (that.sendData === '') { return; } this.socket.send(that.sendData); that.sendData = ''; },Copy the code

The above code is not complete, if you need to see the complete code, contact me.