<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何快速實現(xiàn)一個聊天室?

          共 15890字,需瀏覽 32分鐘

           ·

          2021-05-20 04:32

          如何快速實現(xiàn)一個聊天室?

          聊天室

          前些天做了一個網(wǎng)站:https://modubox.cn 其中有個群聊插件,許多人問如何實現(xiàn)的。這里簡單說下,為了快速完成群聊功能,我選擇從最簡單的 WebSocket 開始。

          什么是WebSocket ?

          既然要使用它,就需要了解一下它吧。WebSocket其實也是一種基于TCP的網(wǎng)絡(luò)協(xié)議,它與HTTP協(xié)議最大的不同是:是一種雙向通信協(xié)議,在建立連接后,WebSocket服務(wù)器端和客戶端都能主動向?qū)Ψ桨l(fā)送或接收數(shù)據(jù),而HTTP協(xié)議只能客戶端主動發(fā)起通信。

          所以WebSocket能夠用于聊天,當(dāng)然其他地方也能應(yīng)用,如果做客服系統(tǒng)或推送消息都可以從這里開始。

          如何實現(xiàn)單聊/群聊?

          群聊:所有客戶端的消息發(fā)送到服務(wù)器,服務(wù)端將消息發(fā)送給所有客戶端。

          單聊:WebSocket客戶端之間是無法直接通信的,想要通信,必須由服務(wù)端轉(zhuǎn)發(fā)。

          群聊單聊

          實現(xiàn)

          1. 引入WebSocket的支持

          我們使用當(dāng)前最流行的Spring Boot框架構(gòu)建項目,然后引入Spring Boot 對 WebSocket 的支持:

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

          2. 開啟WebSocket

          @Configuration
          public class WebSocketConfig {

              @Bean
              public ServerEndpointExporter serverEndpointExporter() {
                  return new ServerEndpointExporter();
              }
          }

          3. 服務(wù)端

          這里主要有以下幾點:

          1. 聲明服務(wù)端點路徑
          2. 存儲所有連接用戶,等待匹配用戶
          3. 連接 onOpen,消息OnMessage,關(guān)閉onClose,錯誤onError 方法
          4. 發(fā)送消息給特定連接者
          @ServerEndpoint(value = "/websocket/random/")
          @Component
          public class ChatRandomServer {
              //所有連接
              public static ConcurrentHashMap<String, ChatRandomServer> webSocketSet = new ConcurrentHashMap<>();
              //與某個客戶端的連接會話,需要通過它來給客戶端發(fā)送數(shù)據(jù)
              private Session session;
              //所有在配對的ID
              private static List<String> webSocketLiveList = new CopyOnWriteArrayList();
              //自己的id標識
              private String id = "";
              //連接對象的id標識
              private String toUser = "";

              /**
               * 連接建立成功調(diào)用的方法
               */

              @OnOpen
              public void onOpen(Session session) {
                  session.setMaxIdleTimeout(3600000);
                  this.session = session;
                  //獲取用戶ip
                  String ip = IpUtil.getRemoteAddress(session);
                  this.id = ip;
                  ChatRandomServer put = webSocketSet.put(this.id, this);
                  //如果已經(jīng)在隊里,就不去找對象
                  if (put == null) {
                      try {
                          if (pair()) {
                              sendMessage("匹配成功");
                          }
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  } else {
                      try {
                          sendMessage("匹配失敗");
                          webSocketSet.remove(this.id); 
                          session.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }

                  }
                  log.info("用戶{}加入!當(dāng)前在線人數(shù)為: {}"this.id, webSocketSet.size());

              }

              /**
               * 連接關(guān)閉調(diào)用的方法
               */

              @OnClose
              public void onClose() {
                  ChatRandomServer UserId = webSocketSet.get(toUser);
                  webSocketLiveList.remove(this.id);
                  if (UserId != null) {
                      try {
                          sendToUser(session, "對方已離開", toUser);
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
                  webSocketSet.remove(this.id);
                  log.info("{}連接關(guān)閉!當(dāng)前在線人數(shù):{}, 當(dāng)前在匹配的人數(shù):{}" ,this.id,webSocketSet.size(), webSocketLiveList.size());
              }

              /**
               * 收到客戶端消息后調(diào)用的方法
               *
               * @param message 客戶端發(fā)送過來的消息
               */

              @OnMessage
              public void onMessage(String message, Session session) {
                  log.info("來自 {} 的消息: {}"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("發(fā)生錯誤");
                  error.printStackTrace();
                  try {
                      SendSelf(session,"服務(wù)器出現(xiàn)錯誤");
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }

              /**
               * 發(fā)送消息給自己
               */

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

              /**
               * 發(fā)送信息給指定ID用戶
               */

              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, "發(fā)送失敗");
                  }
              }

              /**
               * 通知除了自己之外的所有人
               */

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

              /**
               * 發(fā)送信息給所有人
               */

              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) {
                      //隨機匹配一個
                      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, "配對成功", toUser);
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                      webSocketLiveList.remove(nextInt);
                      return true;
                  }
                  //沒有匹配的,則將自己加入等待匹配隊列
                  webSocketLiveList.add(id);
                  return false;
              }
          }

          4. 前端支持

           start: function ({
                  if (typeof (WebSocket) === "undefined") {
                    alert("您的瀏覽器不支持socket")
                  } else {
                    // 實例化socket
                    this.socket = new WebSocket(`ws://localhost:8082/websocket/room`);
                    // 監(jiān)聽socket連接
                    this.socket.onopen = this.open
                    // 監(jiān)聽socket錯誤信息
                    this.socket.onerror = this.error
                    // 監(jiān)聽socket消息
                    this.socket.onmessage = this.getMessage
                    this.socket.onclose = this.close
                  }
                },
                openfunction ({
                },
                errorfunction ({
                },
                getMessagefunction (obj{
                  //接收信息后根據(jù)不同情況不同處理方式
                  let data = JSON.parse(obj.data);
                  if (data.code === 1) {
                  } else if (data.code === 2) {
                  } else {
                  }
                },
                closefunction (e{
                },

                doSendfunction ({
                  if (that.sendData === '') {
                    return;
                  }
                  this.socket.send(that.sendData);
                  that.sendData = '';
                },

          以上代碼不完整,如果需要看下完整代碼,聯(lián)系我。


          瀏覽 43
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黑人大鷄巴XXX69式 | 国产乱伦视频网站 | 中国字幕欧美操逼图 | 狠狠撸大香蕉 | 无码aaa |