1. 程式人生 > >WebSocket實現web即時通信(後端nodejs實現)

WebSocket實現web即時通信(後端nodejs實現)

tcp ica pri har == bootstra query gif 不容易

WebSocket實現web即時通信

一、首先看一下,HTTP、ajax輪詢、long poll和WebSocket的區別:

1、HTTP 協議(短連接):一個 Request 一個 Response。缺陷:通信只能由客戶端發起。
--------------------------------------------------------------------------------
2、ajax輪詢:
ajax輪詢的原理非常簡單,讓瀏覽器隔個幾秒就發送一次請求,詢問服務器是否有新信息。
輪詢的效率低,非常浪費資源(因為必須不停連接,或者 HTTP 連接始終打開)
--------------------------------------------------------------------------------
3、long poll:原理跟ajax輪詢差不多,都是采用輪詢的方式,不過采取的是阻塞模型(一直打電話,沒收到就不掛電話),也就是說,客戶端發起連接後,如果沒消息,就一直不返回Response給客戶端。直到有消息才返回,返回完之後,客戶端再次建立連接,周而復始。基於事件的觸發,一個事件接一個事件。long poll需要很高的並發,體現了同時容納請求的能力。
--------------------------------------------------------------------------------
4、WebSocket:是HTML5一種新的協議。它實現了瀏覽器與服務器全雙工通信(full-duplex)。一開始的握手需要借助HTTP請求完成。WebSocket的優勢在於他的高實時性,以及傳輸過程中的低的資源消耗!
握手成功後,數據就直接從 TCP 通道傳輸,與 HTTP 無關了。Websocket的數據傳輸是frame形式傳輸的。
WebSocket 協議在2008年誕生,2011年成為國際標準。所有瀏覽器都已經支持了。
它的最大特點就是,服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發送信息,是真正的雙向平等對話,屬於服務器推送技術的一種。
其他特點包括:
(1)建立在 TCP 協議之上,服務器端的實現比較容易。
(2)與 HTTP 協議有著良好的兼容性。默認端口也是80和443,並且握手階段采用 HTTP 協議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務器。
(3)數據格式比較輕量,性能開銷小,通信高效。
(4)可以發送文本,也可以發送二進制數據。
(5)沒有同源限制,客戶端可以與任意服務器通信。
(6)協議標識符是ws(如果加密,則為wss),服務器網址就是 URL。

關於WebSocket的更多介紹可以參考
阮一峰——WebSocket 教程http://www.ruanyifeng.com/blog/2017/05/websocket.html

===============================================================================
二、通過nodejs和javascript實現一個網頁聊天室

(參考:博客https://blog.csdn.net/u010136741/article/details/51612594?utm_source=copy;作者:柳木木_kylin )
主要包括,聊天,改用戶名,查看其他用戶在線狀態的功能。
大致流程為,用戶訪問網頁,即進入聊天狀態,成為新遊客,通過底部的輸入框,可以輸入自己想說的話,點擊發布,信息呈現給所有在聊天的人的頁面。用戶可以實時修改自己的昵稱,用戶離線上線都會實時廣播給其他用戶!
javascript 部分,連接websocket成功之後,主要是監聽數據返回,和發送數據。
當用戶編輯好內容,點擊發送按鈕是調用sendMessage方法,發送數據,如果需要修改昵稱,則發送數據格式為"/nick 昵稱"。
當服務器返回數據到客戶端,我們通過appendLog方法對數據做處理,根據type字段,判斷是顯示用戶離線在線信息,還是顯示聊天信息。最後更新在線人數。

服務器端:WebSocket_chart_server.js

var WebSocket = require(ws);
var WebSocketServer = WebSocket.Server,
    wss = new WebSocketServer({port: 8180});
var uuid = require(node-uuid);
 
var clients = [];
 
function wsSend(type, client_uuid, nickname, message,clientcount) {
  for(var i=0; i<clients.length; i++) {
    var clientSocket 
= clients[i].ws; if(clientSocket.readyState === WebSocket.OPEN) { clientSocket.send(JSON.stringify({ "type": type, "id": client_uuid, "nickname": nickname, "message": message, "clientcount":clientcount, })); } } } var clientIndex = 1; wss.on(
connection, function(ws) { var client_uuid = uuid.v4(); var nickname = "遊客"+clientIndex; clientIndex+=1; clients.push({"id": client_uuid, "ws": ws, "nickname": nickname}); console.log(client [%s] connected, client_uuid); var connect_message = nickname + " 來了"; wsSend("notification", client_uuid, nickname, connect_message,clients.length); ws.on(message, function(message) { if(message.indexOf(/nick) === 0) { var nickname_array = message.split( ); if(nickname_array.length >= 2) { var old_nickname = nickname; nickname = nickname_array[1]; var nickname_message = "用戶 " + old_nickname + " 改名為: " + nickname; wsSend("nick_update", client_uuid, nickname, nickname_message,clients.length); } } else { wsSend("message", client_uuid, nickname, message,clients.length); } }); var closeSocket = function(customMessage) { for(var i=0; i<clients.length; i++) { if(clients[i].id == client_uuid) { var disconnect_message; if(customMessage) { disconnect_message = customMessage; } else { disconnect_message = nickname + " 走了"; } clients.splice(i, 1); wsSend("notification", client_uuid, nickname, disconnect_message,clients.length); } } } ws.on(close, function() { closeSocket(); }); process.on(SIGINT, function() { console.log("Closing things"); closeSocket(Server has disconnected); process.exit(); }); });

web端:WebSocket_chart_web.html

<!DOCTYPE html>
<html lang="cn">
<head>
    <title>WebSocket chart application</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/4.0.0-alpha.2/css/bootstrap.css">
    <link rel="stylesheet" href="http://cdn.bootcss.com/tether/1.3.2/css/tether.css"/>
    <script src="http://cdn.bootcss.com/jquery/2.2.4/jquery.js" ></script>
    <script src="http://cdn.bootcss.com/tether/1.3.2/js/tether.js"></script>
    <script src="http://cdn.bootcss.com/bootstrap/4.0.0-alpha.2/js/bootstrap.js"></script>
    <script>
        var ws= new WebSocket(ws://localhost:8180);
        var nickname;
        ws.onopen = function(e){
            console.log(Connection to server opened);
        }
          function appendLog(type,nickname, message,clientcount) {
                  var messages = document.getElementById(messages);
                  var messageElem = document.createElement("li");
                  var preface_label;
            if(type===notification) {
                          preface_label = "<span class=\"label label-info\">*</span>";
                      } else if(type===nick_update) {
                          preface_label = "<span class=\"label label-warning\">*</span>";
                      } else {
                          preface_label = "<span class=\"label label-success\">" + nickname + "</span>";
                      }
                  var message_text = "<h2>" + preface_label + "  " + message + "</h2>";
                  messageElem.innerHTML = message_text;
                  messages.appendChild(messageElem);
            var count_people = document.getElementById("count_people");
                        count_people.innerHTML = clientcount;
 
            }
        ws.onmessage = function(e){
            var data = JSON.parse(e.data);
            nickname = data.nickname;
                  appendLog(data.type,data.nickname, data.message,data.clientcount);
                console.log("ID: [%s] = %s", data.id, data.message);
 
 
        }
        function sendMessage(){
            var message = $(#message).val().trim();
            if(message.length<1){
                alert("不能發送空內容!");
                return;
            }
            ws.send($(#message).val());
            $(#message).val("");
            $(#message).focus();
            console.log(ws.bufferedAmount);
        }
    </script>
</head>
<body lang="cn">
    <div class="vertical-center">
    <div class="container">
        <h2>多人在線聊天DEMO</h2>
    <hr />
    <p>當前在線人數:<span id="count_people">0</span></p>
     <ul id="messages" class="list-unstyled">
 
        </ul>
        <hr />
       <form role="form" id="chat_form" onsubmit="sendMessage(); return false;">
            <div class="form-group">
                <input class="form-control" type="text" name="message" id="message"
                      placeholder="輸入聊天內容" value="" autofocus/>
            </div>
               <button type="button" id="send" class="btn btn-primary"
          onclick="sendMessage();">發送!</button>
    </form>
    </div>
    </div>
</body>
</html>

WebSocket實現web即時通信(後端nodejs實現)