1. 程式人生 > >nodejs-websocket 實現單聊和群聊

nodejs-websocket 實現單聊和群聊

nodejs-websocket 實現單聊和群聊

下載nodejs-websocket
https://github.com/sitegui/nodejs-websocket
最新公司有需求交給我一個任務,研究下關於websocket的即時通訊。寫了一個在上面的基礎上有優化了介面,也增加了功能
Demo地址
https://github.com/zhouyujuan/nodejs-websocket




使用nodejs-websocket的步驟
1、npm init 建立package.json
2、sudo npm install nodejs-websocket 就可以了
3、建立一個wsServer.js 是伺服器檔案
4、伺服器端的程式碼可以先看

https://github.com/sitegui/nodejs-websocket
上面的使用方法。
5、啟動服務、node wsServer.js

wsServer.js 也就是伺服器的程式碼

我們要先載入nodejs-websocket

var ws = require("nodejs-websocket")

// Scream server example: "hi" -> "HI!!!"
建立一個server
var server = ws.createServer(function (conn) {
    console.log("New connection")
接受到傳送的訊息
    conn.on
("text", function (str) { console.log("Received "+str) conn.sendText(str.toUpperCase()+"!!!") }) 關閉時觸發的訊息 conn.on("close", function (code, reason) { console.log("Connection closed") }) }).listen(8001)

在服務端,接受到發起會話的訊息時需要做很多的處理。判斷會話所在的群組,判斷會話物件的狀態。等。
我在這裡做的處理的思路
1、在chat介面發出了會話請求,這裡會把發起會話人的基本資訊整合成一個物件傳送到伺服器
// 連線成功建立的回撥方法

    websocket.onopen = function(e) {
        // 建立連線後,要根據頁面的url得知發起會話的人是想給誰發,或者在那個群裡發
        var url = window.location.href;
        var splitobj = spliturl(url);
        user.name = splitobj.username;
        user.group = splitobj.groupnumber;
        if (user.group == undefined) {
            user.lineType = 1; //單聊
        } else {
            user.lineType = 0; //群聊
        }
        user.type = "enter";
        user.toname = splitobj.toname;
        websocket.send(JSON.stringify(user));
        // 這裡是把發起會話的人的資訊告訴伺服器
        // 傳送訊息
        document.getElementById("sendBtn").onclick = function() {
            var txt = document.getElementById("sendText").value;
            document.getElementById('sendText').value = '';
            if (txt) {
                user.type = "message";
                user.data = txt;
                websocket.send(JSON.stringify(user));
            }
        }
    }

這裡的資訊包括了發起會話的人的
姓名(name)
傳送給誰的(toname)這個在單聊的時候用到
群聊的id(group)群聊的id
發起會話的型別:(type)enter(進入)、 message(發訊息)、leave(離開)

伺服器接受到訊息後

 var user;
    conn.on("text", function(str) {
        // 接收到客戶端的訊息時的處理
        // 這裡的列印會在終端顯示出來
        user = JSON.parse(str);
         // 這裡相當於在有資料庫情況下的一個查表的過程
         // 當有人在群裡說話的時候,表示這個人是線上狀態、
         // 這樣他的好友在給他單獨發訊息的時候,傳送的資訊不回在這個群聊的會話列表展示
        if (user.group != undefined) {
            if (user.group == 1) {
                if (groups[0].members.contains(user.name)) {
                    console.log('可以進入群聊');
                    onlines.push(user.name);  //群聊的人線上狀態的標識
                } else {
                    return;
                }
            } else if (user.group == 2) {
                if (groups[1].members.contains(user.name)) {
                    console.log('可以進入群聊');
                    onlines.push(user.name);
                } else {
                    return;
                }
            }
        } else {
            connections.push(user); // 如果不是群聊是單聊
        }

        // 當發起單聊的人超過1個人的時候,就要確定單聊的路線
        if (connections.length > 1) {
            for (var i = 0; i < connections.length; i++) {
                for (var j = i + 1; j < connections.length; j++) {
                    // 這裡是判斷單聊的路線,toname是要傳送的人和要接受的人是否一樣
                    if (connections[i].toname == connections[j].name &&
                        connections[j].toname == connections[i].name) {
                        signallines.push(connections[j].toname);
                        signallines.push(connections[j].name);

                    }
                }
            }
        }
       // 下面這些就是通過上面的資訊,組織下要傳送的資訊

        var mes = {};
        mes.type = user.type;
        if (mes.type == 'enter') {
            mes.data = user.name;
        } else {
            mes.data = user.data;
        }
        mes.num = user.count;
        mes.name = user.name; //發起會話的人的姓名  這裡最好使用id
        mes.toname = user.toname; //只會在單聊的時候存在,要傳送給誰,也最好用id
        mes.groupnumber = user.group; //群聊的時候,群聊的id

        if (user.group != undefined) {
            // 你要單獨給好友聊天,這裡檢測好友是否在群聊
            if (onlines.contains(mes.toname)) {
                console.log('我要傳送的物件線上')
                 broadcast(JSON.stringify("好友在忙碌"));
            } else {
                broadcast(JSON.stringify(mes));
            }
        } else {
            // 你要單獨給好友聊天,這裡檢測好友是否在和別人聊天
            if (signallines.contains(mes.toname) && signallines.contains(mes.name)) {
                broadcast(JSON.stringify(mes));
            } else {
                console.log('我要傳送的---物件線上')
                broadcast(JSON.stringify("好友在忙碌"));       
            }
        }
        console.log('broadcast', JSON.stringify(mes));
    })

伺服器接受到訊息後。會判斷這個會話是要在哪裡發起(在群裡,單聊的)
(1)如果帶有群號,
驗證下之後就可以吧這個user放到群聊線上的陣列中(online)標識了一個狀態;
(2)如果是單聊
放入單聊的陣列中 connections.
對單聊的陣列進行判斷,如果大於兩個人,我們需要在單聊的陣列中找到配對的
也就是陣列中一個物件A的toname 和 另一個物件B 的 name 相等 並且,B的toname和Aname相等。
這樣就配對成功了

其實,這部分如果建了資料庫處理起來很好,這裡只是Dmeo所以沒有做詳盡的處理。

(3)通過(1)和(2)的操作我們基本知道了發起會話的人的應該 把他的會話轉向哪裡了
1、是轉到那個群
2、是轉到那個人哪裡
3、還是告訴他好友在忙,無法傳送訊息

當會話關閉是

   conn.on("close", function(code, reason) {
        clientCount = 0;
        var mes = {}
        mes.type = "leave"
        mes.data = user.name + 'leave';
        // 離開群組或者離開單聊的時候,要把狀態清空
        onlines.remove(user.name);
        connections.remove(user.name);
        signallines.remove(user.name);
        broadcast(JSON.stringify(mes))
    })

當離開的時候也清除記錄,改變狀態
傳送訊息的方法。

function broadcast(str) {
    console.log('str', str);
    // 取到server下面的所有連線
    server.connections.forEach(function(connection) {
        connection.sendText(str);
    })
}