分享基於 websocket 網頁端聊天室

博客地址:https://ainyi.com/67css

有一個月沒有寫博客了,也是由於年前需求多、回家過春節的緣由,如今返回北京的次日,想一想,應該也要分享技術專題的博客了!!html

主題

基於 websocket 網頁端聊天室前端

WebSocket 協議是基於 TCP 的一種新的網絡協議。它實現了瀏覽器與服務器全雙工 (full-duplex) 通訊——容許服務器主動發送信息給客戶端。java

使用 java 開發後臺jquery

須要導入一個jar包:javax.websocket-api-1.0-rc4.jarweb

後臺代碼

package com.krry.socket;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
 
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
 
//該註解用來指定一個URI,客戶端能夠經過這個URI來鏈接到WebSocket。相似Servlet的註解mapping。無需在web.xml中配置。
@ServerEndpoint("/websocket")
public class MyWebSocket {
    //靜態變量,用來記錄當前在線鏈接數。應該把它設計成線程安全的。
    private static int onlineCount = 0;
     
    //concurrent包的線程安全Set,用來存放每一個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通訊的話,可使用Map來存放,其中Key能夠爲用戶標識
    private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
     
    //與某個客戶端的鏈接會話,須要經過它來給客戶端發送數據
    private Session session;
     
    /**
     * 鏈接創建成功調用的方法
     * @param session  可選的參數。session爲與某個客戶端的鏈接會話,須要經過它來給客戶端發送數據
     */
    @OnOpen
    public void onOpen(Session session){
        this.session = session;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在線數加1
        System.out.println("有新鏈接加入!當前在線人數爲" + getOnlineCount());
    }
     
    /**
     * 鏈接關閉調用的方法
     */
    @OnClose
    public void onClose(){
        webSocketSet.remove(this);  //從set中刪除
        subOnlineCount();           //在線數減1    
        System.out.println("有一鏈接關閉!當前在線人數爲" + getOnlineCount());
    }
     
    /**
     * 收到客戶端消息後調用的方法
     * @param message 客戶端發送過來的消息
     * @param session 可選的參數
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("來自客戶端的消息:" + message);
         
        //羣發消息
        for(MyWebSocket item: webSocketSet){             
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
    }
     
    /**
     * 發生錯誤時調用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("發生錯誤");
        error.printStackTrace();
    }
     
    /**
     * 這個方法與上面幾個方法不同。沒有用註解,是根據本身須要添加的方法。
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException{
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }
 
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
 
    public static synchronized void addOnlineCount() {
        MyWebSocket.onlineCount++;
    }
     
    public static synchronized void subOnlineCount() {
        MyWebSocket.onlineCount--;
    }
}

前端代碼

注意

前端須要實現這幾個方法:api

// 註冊事件
  // 監聽打開鏈接
  ws.onopen = function(){
    openWs();
  };
  // 監聽消息
  ws.onmessage = function(event){
    msgWs(event);
  };
  // 監聽關閉鏈接
  ws.onclose = function(){
    closeWs();
  };
  // 監聽發送錯誤
  ws.onerror = function(){
    errorWs();
  };

具體代碼

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!doctype html>
<html>
  
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    <meta name="keywords" content="">
    <meta name="description" content="">
    <title>
      基於Java服務器端的消息主動推送技術揭祕 --krry
    </title>
    <link rel="stylesheet" href="css/animate.css" />
    <link rel="stylesheet" type="text/css" href="css/sg.css" />
    <style>
      *{margin:0;padding:0;} body{background:url("images/5.jpg");background-size:cover;}
      h1{margin-top:50px;text-align:center;color:#fff;text-shadow:1px 1px 1px
      #000;font-family:-webkit-body;font-size:24px;} .box{width:700px;margin:20px
      auto;} .box span{color:#f60;font-size:16px;font-family:"微軟雅黑";} .box .shu{text-indent:1em;height:24px;font-family:"微軟雅黑";border:0;outline:none;font-size:14px;}
      .box .add{width:300px;margin-right:24px;} .box .user{width:200px;} .box
      .btn{width:80px;height:34px;color:#fff;background:#6c0;border:0;outline:none;cursor:pointer;margin-top:20px;font-size:16px;font-family:"微軟雅黑";}
      .box .area{line-height: 29px;height:280px;width:680px;padding:10px;overflow:auto;font-size:16px;font-family:"微軟雅黑";margin:20px
      0;outline:none;box-shadow:1px 2px 18px #000} .box .setex{text-indent:1em;height:28px;border:1px
      solid #6c0;width:618px;outline:none;float:left;font-family:"微軟雅黑";} .box
      .send{font-size:14px;width:80px;height:30px;color:#fff;background:#6c0;border:0;outline:none;cursor:pointer;font-family:"微軟雅黑";}
    </style>
  </head>
  
  <body>
    <h1>
      基於Java服務器端的消息主動推送技術揭祕 --krry
    </h1>
    <div class="box">
      <span>
        服務器地址:
      </span>
      <input type="text" class="shu add" value="www.ainyi.com/krry_NetChat/websocket"
      readonly/>
      <span>
        用戶名:
      </span>
      <input type="text" class="shu user" value="匿名" />
      <input type="button" value="鏈接" class="btn" />
      <div class="area" id="boxx">
      </div>
      <div class="c_cen">
        <input type="text" class="setex" />
        <input type="button" value="發送" class="send">
      </div>
    </div>
    <script src="js/jquery-1.11.1.min.js">
    </script>
    <script src="js/sg.js">
    </script>
    <script src="js/sgutil.js">
    </script>
    <script>
      var close = true;
      var ws;
      $(function() {
        $(".c_cen").hide();
        //首先判斷瀏覽器是否支持webSocket,支持h5的瀏覽器纔會支持
        if (window.WebSocket) {
          printMsg("您的瀏覽器支持WebSocket,您能夠嘗試鏈接到聊天服務器!", "OK");
        } else {
          printMsg("您的瀏覽器不支持WebSocket,請選擇其餘瀏覽器!", "ERROR");
          //設置按鈕不可點擊
          $(".btn").attr("disabled", "true");
        }
      });
      //打印信息
      function printMsg(msg, msgType) {
        if (msgType == "OK") {
          msg = "<span style='color:green'>" + msg + "</span>";
        }
        if (msgType == "ERROR") {
          msg = "<span style='color:red'>" + msg + "</span>";
        }
        $(".area").append(msg + "<br/>");
        var boxx = document.getElementById("boxx");
        boxx.scrollTop = boxx.scrollHeight; //使滾動條一直在底部
      }

      //打開Socket
      function openWs() {
        printMsg("連接已創建", "OK");
        ws.send("【" + $(".user").val() + "】已進入聊天室");
        $(".c_cen").show();
      }

      //接收消息的時候
      function msgWs(e) {
        printMsg(e.data);
      }
      //關閉鏈接
      function closeWs() {
        $(".btn").val("鏈接");
        $(".c_cen").hide();
      }
      //產生錯誤
      function errorWs() {
        printMsg("您與服務器鏈接錯誤...", "ERROR");
      }

      //點擊發送按鈕
      $(".send").click(function() {
        var text = $(".setex").val();
        if (text == null || text == "") return;
        $(".setex").val("");
        ws.send("【" + $(".user").val() + "】:" + text);
      });

      //點擊鏈接
      $(".btn").click(function() {
        if ($(".add").val() && $(".user").val()) {
          if (close) {
            printMsg("正在準備鏈接服務器,請稍等...");
            var url = "wss://" + $(".add").val();
            if ("WebSocket" in window) {
              ws = new WebSocket(url);
            } else if ("MozWebSocket" in window) {
              ws = new MozWebSocket(url);
            }
            //已鏈接
            $(".btn").val("斷開");
            close = false;

            //註冊事件
            ws.onopen = function() {
              openWs();
            };
            ws.onmessage = function(event) {
              msgWs(event);
            };
            ws.onclose = function() {
              closeWs();
            };
            ws.onerror = function() {
              errorWs();
            };

            //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket鏈接,防止鏈接還沒斷開就關閉窗口,server端會拋異常。
            window.onbeforeunload = function() {
              ws.send("【" + $(".user").val() + "】離開了聊天室");
              close = true;
              ws.close();
            };

          } else {
            ws.send("【" + $(".user").val() + "】離開了聊天室");
            close = true;
            ws.close();
          }
        } else {
          $.tmDialog.alert({
            open: "left",
            content: "服務器地址和用戶名不能爲空哦...",
            title: "提示哦~~~"
          });
        }
      });

      //回車鍵
      $(".setex").keypress(function(event) {
        if (event.keyCode == 13) {
          $(".send").trigger("click");
        }
      });
    </script>
  </body>

</html>

到這裏大功告成瀏覽器

聊天方法

  1. 打開兩個窗口輸入項目地址進行聊天
  2. 能夠把連接發給朋友打開,進行聊天

來一波截圖

移動端

在線演示

PC 端:https://www.ainyi.com/krry_NetChat 移動端:https://www.ainyi.com/krry_NetChatPho安全

打完收工~服務器

博客地址:https://ainyi.com/67

相關文章
相關標籤/搜索