乐趣区

关于websocket:node-使用websocket实现一个简易聊天

应用 nodejs 实现一个简易版聊天程序.

client 端

package.json

{
  "name": "client",
  "version": "1.0.0",
  "description": "","main":"server.js","scripts": {"test":"echo \"Error: no test specified\" && exit 1","start":"node server.js"},"keywords": [],"author":"",
  "license": "ISC",
  "dependencies": {"express": "^4.18.2"}
}

server.js

const express = require("express");
const path = require("path");
const port = 4000;
const app = new express();

app.use(express.static(path.resolve(__dirname, "public")));


app.listen(port, () => {console.log(`Client server run at ${port}.`);
})

public/index.html

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .chat {
            display: flex;
            flex-direction: column;
            row-gap: 10px;
        }

        .row {
            display: flex;
            width: 400px;
            column-gap: 10px;
        }

        #display {
            width: 100%;
            height: 300px;
            background-color: white;
            border: 1px solid black;
            overflow-y: auto;
        }

        #input {
            height: 100px;
            width: 400px;
        }
    </style>
</head>

<body>
    <div class="chat">
        <div class="row">
            <input id="sender" type="text" placeholder="发送方" />
            <button onclick="onConnect()">connect</button>
            <button onclick="onDisConnect()">disconnect</button>
            <button onclick="onClear()">clear</button>
        </div>
        <div class="row">
            <textarea id="display" readonly></textarea>
        </div>
        <div class="row">
            <textarea id="input" placeholder="发送音讯"></textarea>
            <div>
                <input id="receiver" placeholder="接管方" />
                <button onclick="onSend()">send</button>
            </div>
        </div>
    </div>

    <script>
        let senderDom = document.getElementById("sender");
        let receiverDom = document.getElementById("receiver");
        let inputDom = document.getElementById("input");
        let displayDom = document.getElementById("display");
        let websocketIp = "ws://localhost:4005?name=";
        let ws;

        function onConnect() {if (ws) {onDisplay(`You are already online.`);
                return;
            }

            let sender = senderDom.value;
            ws = new WebSocket(websocketIp + sender);
            ws.onopen = (e) => {clearDisplay();
                onDisplay(`You are online.`);
            }

            ws.onclose = (e) => {onDisplay(`You are offline.`);
                ws = undefined;
            }

            ws.onmessage = (e) => {const obj = JSON.parse(e.data);
                const {type, data} = obj;

                if (type == "status") {const { user, status} = data;
                    onDisplay(`${user} is ${status == 0 ? "offline" : "online"}.`);
                } else if (type == "message") {const { sender, message} = data;
                    onDisplay(`${sender}:${message}`);
                }
            }
        }

        function onDisConnect() {if (!ws) {onDisplay(`You are offline,please connect first.`);
                return;
            }

            ws.close();}

        function onClear() {clearDisplay();
        }

        function onSend() {if (!ws) {onDisplay(`You are offline,please connect first.`);
                return;
            }

            let sender = senderDom.value;
            let receiver = receiverDom.value;
            let message = inputDom.value;
            let msg = JSON.stringify({receiver: receiver, message: message});
            ws.send(msg);
            onDisplay(`${sender}:${message}`);
        }

        //utils
        function onDisplay(value) {
            displayDom.value += value + "\n\n";
            displayDom.scrollTop = displayDom.scrollHeight;
        }

        function clearDisplay() {displayDom.value = "";}

    </script>
</body>

</html>

server 端

package.json

{
  "name": "server",
  "version": "1.0.0",
  "description": "","main":"server.js","scripts": {"test":"echo \"Error: no test specified\" && exit 1","start":"node server.js"},"keywords": [],"author":"",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.2",
    "ws": "^8.11.0"
  }
}

server.js

/**
 * 数据结构
 * get:
 * type message/status
 * data {sender,receriver,message}/{user,status: //0 offline 1 online}
 * 
 * send:
 * {receiver,message}
*/

const MESSAGE_TYPE = {
    MESSAGE: "message",
    STATUS: "status",
};

const STATUS = {
    ONLINE: 1,
    OFFLINE: 0,
}

const Websocket = require("ws");
const url = require("url");
const port = 4005;

const wss = new Websocket.Server({port: port});

wss.on("connection", (ws, req) => {const parameters = url.parse(req.url, true);
    ws.name = parameters.query.name;

    //notice all the client that somebody is login
    wss.clients.forEach(client => {
        //skip self
        if (client.name == ws.name) {return;}

        let msg = JSON.stringify({
            type: MESSAGE_TYPE.STATUS,
            data: {
                status: STATUS.ONLINE,
                user: ws.name,
            }
        });
        client.send(msg)
    })

    ws.on("message", (e) => {const data = JSON.parse(e.toString());
        const {receiver} = data;
        wss.clients.forEach(client => {if (client.name == receiver) {
                let msg = JSON.stringify({
                    type: MESSAGE_TYPE.MESSAGE,
                    data: {
                        ...data,
                        sender: ws.name,
                    },
                })
                client.send(msg);
            }
        })
    })

    ws.on("close", (e) => {
        wss.clients.forEach(client => {
            let msg = JSON.stringify({
                type: MESSAGE_TYPE.STATUS,
                data: {
                    status: STATUS.OFFLINE,
                    user: ws.name,
                }
            });
            client.send(msg)
        })
    })
})

演示成果

退出移动版