nodejs+websocket實時聊天系統


介紹下websocket:

webSocket協議本質上是一個基於tcp的協議;

建立一個websocket連接,大體的過程:

1.客戶端瀏覽器首先向服務器發起一個http請求,這個請求和平常的請求有什么不同呢?

多了一點附加頭信息:"upgrade:web Socket” 表明我這申請的是一個websocket的http請求;

2.服務器收到請求后,解析這些附加的頭信息,然后產生應答信息返回給客戶端,這樣,連接就建立了;

3.雙方就可以通過這個連接通道自由的信息傳遞,這個連接會一直存在,直到一方自動關閉連接;

 

客戶端到服務端:

GET /demo HTTP/1.1

Host: example.com

Connection: Upgrade

Sec-WebSocket-Key2: 12998 5 Y3 1 .P00

Upgrade: WebSocket

Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5

Origin: http://example.com

[8-byte security key]

 

服務端到客戶端:

HTTP/1.1 101 WebSocket Protocol Handshake

Upgrade: WebSocket

Connection: Upgrade

WebSocket-Origin: http://example.com

WebSocket-Location: ws://example.com/demo

[16-byte hash response]

 

從客戶端到服務端請求的信息里面包含:‘Sec-webSocket-key1","Sec-WebSocket-key2"和“[8-byte security key]”這樣的信息;這是客戶端瀏覽器需要向服務端提供的握手信息,服務端解析這些頭信息,並且在握手的過程中依據這些信息生成一個16位的安全密鑰並返回給客戶端,以表明服務器端獲取了客戶端的請求;

大致步驟:

1.	逐個字符讀取 Sec-WebSocket-Key1 頭信息中的值,將數值型字符連接到一起放到一個臨時字符串里,同時統計所有空格的數量;
2.	將在第 1 步里生成的數字字符串轉換成一個整型數字,然后除以第 1 步里統計出來的空格數量,將得到的浮點數轉換成整數型;
3.	將第 2 步里生成的整型值轉換為符合網絡傳輸的網絡字節數組;
4.	對 Sec-WebSocket-Key2 頭信息同樣進行第 1 到第 3 步的操作,得到另外一個網絡字節數組;
5.	將 [8-byte security key] 和在第 3,第 4 步里生成的網絡字節數組合並成一個 16 字節的數組;
6.	對第 5 步生成的字節數組使用 MD5 算法生成一個哈希值,這個哈希值就作為安全密鑰返回給客戶端,以表明服務器端獲取了客戶端的請求,同意創建 WebSocket 連接

 

 var  wsServer = 'ws://localhost:8888/Demo';  //連接地址
 var  websocket = new WebSocket(wsServer);   //建立連接
 websocket.onopen = function (evt) { onOpen(evt) };  //4個事件
 websocket.onclose = function (evt) { onClose(evt) }; 
 websocket.onmessage = function (evt) { onMessage(evt) }; 
 websocket.onerror = function (evt) { onError(evt) }; 
 function onOpen(evt) { 
 console.log("Connected to WebSocket server."); 
 } 
 function onClose(evt) { 
 console.log("Disconnected"); 
 } 
 function onMessage(evt) { 
 console.log('Retrieved data from server: ' + evt.data); 
 } 
 function onError(evt) { 
 console.log('Error occured: ' + evt.data); 
 }

   瀏覽器的支持情況:

瀏覽器	支持情況
Chrome	Supported in version 4+
Firefox	Supported in version 4+
Internet Explorer	Supported in version 10+
Opera	Supported in version 10+
Safari	Supported in version 5+

 正文來了:基於websocket制作的簡單聊天系統;

client.html:

 <style>
        .kuang {
            width: 600px;
            min-height: 50px;
            max-height: 296px;
            border: 1px solid;
            float: left;
            display: block;
            position: relative;
            overflow-y: scroll;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row">
              <div class="jumbotron  bg-dark">
                <h1 class="jumbotron-heading">WebSocket chat,歡迎使用:</h1>
              </div>
            <div class="input-group text-left">
                <label>輸入用戶名:</label>
                <input type="text" id="name" />
                <button id="conn">連接</button>
                <button id="close">斷開</button>
            </div>
            <div class="input-group text-muted">
                <div class="kuang" id="mess"></div>
            </div>
         <hr class="featurette-divider">
            <div class="input-group text-left">
                <input type="text" class="value" id="value1" />
                <button id="send">發送</button>
            </div>
        </div>
    </div>

 簡單的界面,大致效果就是這樣的:

然后實現邏輯代碼:

 var ws = new WebSocket('ws://127.0.0.1:8082');
                ws.onopen = function (e) {
                    console.log("連接服務器成功");
                }
                ws.onmessage = function (e) {
                    value1.removeAttribute("readOnly");
                    var time = new Date();
                    mess.innerHTML += time.toUTCString() + ":" + e.data + "<br>";
                    document.getElementById("send").onclick = function (e) {
                        ws.send(input.value + "說:" + value1.value);
                        value1.value = " ";
                    }
                    document.onkeydown = function (e) {
                        e = e || window.event;
                        if (e.keyCode == 13) {
                            document.getElementById("send").onclick();
                            return false;
                        }
                    }
                }
                ws.onclose = function (e) {
                    console.log("服務器關閉");
                }
                ws.onerror = function () {
                    console.log("連接出錯");
                }

 連接地址:ws://127.0.0.1:8082  那是哪里來的呢?  (注意http請求則是寫成http://xxx,https請求則是https://xxx;ws當然是ws://xxx);

wbsocket只是客服端,地址當然是從我們的服務端給的呀;

服務端的搭建采用了一個這樣的庫:

nodejs-websocket
 
1.npm isntall -g nodejs-websocket
2.在js頁面引入它 
var ws = require("nodejs-websocket");
3.創建一個服務
var server = ws.createServer(function (conn) {
    conn.on('text', function (str) {
    })

    conn.on("close", function (code, reason) {
        console.log("關閉連接");
    })
    conn.on("error", function (code, reason) {
        console.log("異常關閉");
    });
}).listen(8082);
console.log("websocket連接完畢")

 好了,websocket連接算是建立啦!

下面展示下具體代碼:

client.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="bootstrap-3.3.7-dist/css/bootstrap.min.css" />
    <script src="jquery.min.js"></script>
    <script src="bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    <style>
        .kuang {
            width: 600px;
            min-height: 50px;
            max-height: 296px;
            border: 1px solid;
            float: left;
            display: block;
            position: relative;
            overflow-y: scroll;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row">
              <div class="jumbotron  bg-dark">
                <h1 class="jumbotron-heading">WebSocket chat,歡迎使用:</h1>
              </div>
            <div class="input-group text-left">
                <label>輸入用戶名:</label>
                <input type="text" id="name" />
                <button id="conn">連接</button>
                <button id="close">斷開</button>
            </div>
            <div class="input-group text-muted">
                <div class="kuang" id="mess"></div>
            </div>
         <hr class="featurette-divider">
            <div class="input-group text-left">
                <input type="text" class="value" id="value1" />
                <button id="send">發送</button>
            </div>
        </div>
    </div>
    <script>
        var input = document.getElementById("name");
        var conn = document.getElementById("conn");
        var close = document.getElementById("close");
        var mess = document.getElementById("mess");
        var value1 = document.getElementById("value1");
        var pattern = /^[\u4e00-\u9fa5]{2,10}$/;
        close.disabled = true;
        if (window.WebSocket) {
            conn.onclick = function () {
                if (!pattern.test(input.value)) {
                    alert("名稱不能為空且必須為中文");
                    return;
                }
                var ws = new WebSocket('ws://127.0.0.1:8082');
                conn.disabled = true;
                close.disabled = false;
                ws.onopen = function (e) {
                    console.log("連接服務器成功");
                    ws.send(input.value);
                    input.setAttribute("readOnly", 'true');
                    value1.setAttribute("readOnly", 'true');
                }
                ws.onmessage = function (e) {
                    value1.removeAttribute("readOnly");
                    var time = new Date();
                    mess.innerHTML += time.toUTCString() + ":" + e.data + "<br>";
                    document.getElementById("send").onclick = function (e) {
                        ws.send(input.value + "說:" + value1.value);
                        value1.value = " ";
                    }
                    document.onkeydown = function (e) {
                        e = e || window.event;
                        if (e.keyCode == 13) {
                            document.getElementById("send").onclick();
                            return false;
                        }
                    }
                }
                ws.onclose = function (e) {
                    console.log("服務器關閉");
                }
                ws.onerror = function () {
                    console.log("連接出錯");
                }

                close.onclick = function () {
                    ws.onclose();
                    ws.send(input.value + 'close' + "了連接");
                    input.removeAttribute("readOnly");
                    conn.disabled = false;
                    close.disabled = true;
                }
            }
        }
    </script>
</body>

</html>

 server.js

var ws = require("nodejs-websocket");
console.log("開始建立連接...");
var str1 = null, str2 = null, clientReady = false, serverReady = false;
var a = [];
var server = ws.createServer(function (conn) {
    conn.on('text', function (str) {
          a.push(str);
        if (!clientReady) {
            if (a[0] === str) {
                str1 = conn;
                clientReady = true;
                str1.sendText("歡迎你" + str);
                
            }
        } else if (!serverReady) {
            if (str.indexOf('close') >= 0) {    
                     a.splice(2,1);
                     clientReady = false;
                     str1=null;   
                     return;
                }
            if (a[1] === str) {
                str2 = conn;
                serverReady = true;
                str2.sendText("歡迎你" + str);
                str1.sendText(str + "在線啦,你們可以聊天啦");
                return;
            } 
        } else if (clientReady && serverReady) {
                str2.sendText(str);
                str1.sendText(str);
                if (str.indexOf('close') >= 0) {
                    a.splice(2, a.length);
                    var len = a.length;
                    for (var i = 0; i < len; i++) {
                        // 定位該元素位置
                        if (str.indexOf(a[i])>=0) {     
                           a.splice(i,1);
                           if(i==0){
                               str1=str2;
                           }
                           serverReady = false; 
                           str2=null;
                           return;
                        }
                      
                    } 
                }
            }  
            
            
    })

    conn.on("close", function (code, reason) {
        console.log("關閉連接");
        clientReady = false;
        serverReady = false;
    })
    conn.on("error", function (code, reason) {
        console.log("異常關閉");
    });
}).listen(8082);
console.log("websocket連接完畢")

 實現雙人聊天,client.html開啟兩個窗口就行!

 詳細代碼在github上:

 https://github.com/sulishibaobei/websocket-
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM