【WebSocket&IndexedDB】node+WebSocket&IndexedDB develops a simple chat room

Prologue introduction:

WebSocket is a protocol for full-duplex communication on a single TCP connection that HTML5 began to provide.

In human terms: WebSocket makes data exchange between the client and the server simpler. In the WebSocket API, the browser and the server only need to complete a handshake, and a persistent connection can be created directly between the two. and perform bidirectional data transmission

Now, in order to implement push technology, many websites use Ajax polling. Polling is when the browser issues an HTTP request to the server at a specific time interval (such as every 1 second), and then the server returns the latest data to the client's browser. This traditional model brings obvious shortcomings, that is, the browser needs to continuously send requests to the server. However, HTTP requests may contain long headers, and the real valid data may be only a small part. Obviously, this will be wasteful. A lot of bandwidth and other resources.

The WebSocket protocol defined by HTML5 can better save server resources and bandwidth, and enable more real-time communication.

WebSocket:

  • Common method WebSocket(url): Create a WebSocket object and establish a connection with the specified URL
// 创建WebSocket对象并与服务器建立连接
var socket = new WebSocket("ws://example.com");
  • Common method send(data): sending data to the server
// 向服务器发送数据
function sendData(data) {
   socket.send(data);
   console.log("发送数据:" + data);
}
  • Common method close(code, reason): Actively close the WebSocket connection
// 主动关闭WebSocket连接
function closeConnection() {
   socket.close();
   console.log("关闭WebSocket连接");
}
  • Common events: onopen: Event triggered when a WebSocket connection is successfully opened
// 连接成功时触发的事件
socket.onopen = function(event) {
   console.log("WebSocket连接已打开");
   // 发送数据示例
   socket.send("Hello, server!");
};
  • Common events: onmessage: Events triggered when a message is received from the server
// 接收到消息时触发的事件
socket.onmessage = function(event) {
   var message = event.data;
   console.log("收到消息:" + message);
};
  • Common events: onclose: Event triggered when the WebSocket connection is closed
// 连接关闭时触发的事件
socket.onclose = function(event) {
   console.log("WebSocket连接已关闭");
};
  • Common events:  onerror: Events triggered when an error occurs in the WebSocket connection
// 连接错误时触发的事件
socket.onerror = function(error) {
   console.error("WebSocket错误:" + error);
};

Rendering:

Code display:

index.html

<html>
<head>
    <meta charset="UTF-8">
    <title>webrtc demo</title>
</head>

<body>
    <h1>Websocket简易聊天</h1>
    <div id="app">
        <input id="sendMsg" type="text" />
        <button id="submitBtn">发送</button>
    </div>
</body>
<script type="text/javascript">
    //在页面显示聊天内容
    function showMessage(str, type) {
        var div = document.createElement("div");
        div.innerHTML = str;
        if (type == "enter") {
            div.style.color = "blue";
        } else if (type == "leave") {
            div.style.color = "red";
        }
        document.body.appendChild(div);
    }

    //新建一个websocket
    var websocket = new WebSocket("ws://172.21.2.52:8099");
    //连接建立时触发
    websocket.onopen = function () {
        console.log("已经连上服务器----");
        document.getElementById("submitBtn").onclick = function () {
            // 获取输入的内容
            var txt = document.getElementById("sendMsg").value;
            if (txt) {
                //使用连接发送数据
                websocket.send(txt);
            }
        };
    };
    //连接关闭时触发
    websocket.onclose = function () {
        console.log("websocket close");
    };
    //客户端接收服务端数据时触发
    websocket.onmessage = function (e) {
        var mes = JSON.parse(e.data);   // json格式
        // 渲染
        showMessage(mes.data, mes.type);
    };
</script>

</html>

node.js remember to download: nodejs-websocket dependency

var ws = require("nodejs-websocket")
var port = 8099;
var user = 0;

// 创建一个连接
var server = ws.createServer(function (conn) {
    console.log("创建一个新的连接--------");
    user++;
    // 给连接设置昵称属性
    conn.nickname = "user" + user;
    // 给连接设置文件描述符属性
    conn.fd = "user" + user;
    var mes = {};
    // 消息类型为进入聊天室
    mes.type = "enter";
    // 消息内容为进入提示
    mes.data = conn.nickname + " 进来啦"
    // 广播该消息给所有客户端
    broadcast(JSON.stringify(mes));

    //向客户端推送消息
    conn.on("text", function (str) {
        console.log("回复 " + str)
        // 消息类型为普通消息
        mes.type = "message";
        mes.data = conn.nickname + " 说:    " + str;
        broadcast(JSON.stringify(mes));
    });

    //监听关闭连接操作
    conn.on("close", function (code, reason) {
        console.log("关闭连接");
        mes.type = "leave";
        mes.data = conn.nickname + " 离开了"
        broadcast(JSON.stringify(mes));
    });

    //错误处理
    conn.on("error", function (err) {
        console.log("监听到错误");
        console.log(err);
    });
}).listen(port);

function broadcast(str) {
    server.connections.forEach(function (connection) {
        connection.sendText(str);
    })
}

IndexedDB

IndexedDB (Indexed Database) is a client-side database storage solution provided by browsers. It allows web applications to store large amounts of structured data on the user's device and query and manipulate it offline. IndexedDB uses an object storage model, similar to a relational database, but does not support the SQL query language.

  • open(): Open database connection
let request = window.indexedDB.open("myDatabase", 1);

request.onerror = function(event) {
  console.log("Failed to open database");
};

request.onsuccess = function(event) {
  let db = event.target.result;
  console.log("Database opened successfully");
};
  • createObjectStore(): Create object storage space
let objectStore = db.createObjectStore("messages", { keyPath: "id", autoIncrement: true });
  • createIndex(): Create index
objectStore.createIndex("type", "user", { unique: false });
  • transaction(): start transaction
let transaction = db.transaction(["messages"], "readwrite");
  • objectStore.add(): Add data to object storage space
let objectStore = transaction.objectStore("messages");
let message = { id: 1, type: "text", data: "Hello World", user: "Alice" };

let request = objectStore.add(message);
request.onsuccess = function(event) {
  console.log("Data added successfully");
};
  • objectStore.get(): Get data by primary key
let objectStore = transaction.objectStore("messages");
  
let request = objectStore.get(1);
request.onsuccess = function(event) {
  let data = event.target.result;
  console.log(data);
};
  • objectStore.getAll(): Get all data
let objectStore = transaction.objectStore("messages");

let request = objectStore.getAll();
request.onsuccess = function(event) {
  let data = event.target.result;
  console.log(data);
};
  • objectStore.put(): update data
let objectStore = transaction.objectStore("messages");
let message = { id: 1, type: "text", data: "Hello Updated", user: "Alice" };

let request = objectStore.put(message);
request.onsuccess = function(event) {
  console.log("Data updated successfully");
};
  • objectStore.delete(): delete data
let objectStore = transaction.objectStore("messages");
  
let request = objectStore.delete(1);
request.onsuccess = function(event) {
  console.log("Data deleted successfully");
};
  • clear(): Clear all data in the object storage space
let objectStore = transaction.objectStore("messages");

let request = objectStore.clear();
request.onsuccess = function(event) {
  console.log("Object store cleared successfully");
};

WebSocket plus IndexedDB complete code

WebSocket implements chat, and IndexedDB stores chat data to prevent refresh loss

html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>webrtc demo</title>
</head>

<body>
    <h1>Websocket简易聊天</h1>
    <div id="app">
        <input id="sendMsg" type="text" />
        <button id="submitBtn">发送</button>
        <div id="leaveMessage"></div>
        <div id="chat"></div>
    </div>

    <script type="text/javascript">
        var db, transaction, objectStore;
        // 在页面显示聊天内容
        function showMessage(str, type, user = null, state = 1) {
            var div = document.createElement("div");

            var spanStr = document.createElement("span");
            spanStr.innerHTML = str;

            if (user != null) {
                var spanUser = document.createElement("span");
                spanUser.innerHTML = user;
                div.appendChild(spanUser);
            }

            if (type == "enter") {
                div.style.color = "blue";
            } else if (type == "leave") {
                div.style.color = "red";
            }

            div.appendChild(spanStr);
            document.getElementById("chat").appendChild(div);
            if (state == 1) {
                document.getElementById("chat").appendChild(div);
            } else {
                document.getElementById("leaveMessage").appendChild(div);
            }
        }

        // 创建或打开 IndexedDB 数据库
        var request = window.indexedDB.open("chatDB", 1);
        request.onerror = function () {
            console.log("无法打开数据库");
        };

        request.onupgradeneeded = function (event) {
            //  获取到数据库对象 db
            db = event.target.result;
            //  创建名为 "messages" 的对象存储,并指定 "id" 为键路径,并自动递增生成
            objectStore = db.createObjectStore("messages", { keyPath: "id", autoIncrement: true });
            // 创建一个名为 "type" 的索引,用于根据消息类型进行检索,允许重复值
            objectStore.createIndex("type", "user", { unique: false });
            // 创建一个名为 "data" 的索引,用于根据消息内容进行检索,允许重复值
            objectStore.createIndex("data", "data", { unique: false });
            objectStore.createIndex("state", "state", { unique: false });
            objectStore.createIndex("user", "user", { unique: false });
        };

        request.onsuccess = function (event) {
            db = event.target.result;
            // 新建一个websocket
            var websocket = new WebSocket("ws://172.21.2.52:8099");

            // 连接建立时触发
            websocket.onopen = function () {
                console.log("已经连上服务器----");
               
                document.getElementById("submitBtn").onclick = function () {
                    var txt = document.getElementById("sendMsg").value;
                    if (txt) {
                        websocket.send(JSON.stringify(txt));
                    }
                };
                // 给输入框添加键盘按下事件监听器
                document.getElementById("sendMsg").addEventListener("keydown", function (event) {
                    // 检查按下的键是否是回车键(键码为13)
                    if (event.keyCode == 13) {
                        // 取消回车键的默认行为(避免表单提交等操作)
                        event.preventDefault();
                        var txt = document.getElementById("sendMsg").value;
                        if (txt) {
                            websocket.send(JSON.stringify(txt));
                        }
                    }
                });
            };

            // 连接关闭时触发
            websocket.onclose = function () {
                console.log("websocket close");
            };

            // 客户端接收服务端数据时触发
            websocket.onmessage = function (e) {
                var mes = JSON.parse(e.data); // json格式
                // 渲染
                if (mes.state == 0) {
                    showMessage(mes.data, mes.type, mes.user);
                    saveMessage(mes)
                    document.getElementById("sendMsg").value = ''
                } else {
                    showMessage(mes.data, mes.type);
                }
            };

            function saveMessage(message) {
                let transaction = db.transaction(["messages"], "readwrite");
                let objectStore = transaction.objectStore("messages");
                var saveRequest = objectStore.add(message);
                saveRequest.onsuccess = function () {
                    console.log("消息已保存到 IndexedDB");
                };
                saveRequest.onerror = function () {
                    console.log("保存消息时发生错误");
                };
            }

            function loadMessages() {
                // 创建一个只读事务,该事务用于操作名为 "messages" 的对象存储
                transaction = db.transaction(["messages"], "readonly");
                // 获取对 "messages" 对象存储的引用,以便进行后续的操作
                objectStore = transaction.objectStore("messages");
                // 回一个获取所有数据的请求
                var getAllRequest = objectStore.getAll();

                // 在获取数据成功时触发
                getAllRequest.onsuccess = function () {
                    var messages = getAllRequest.result;
                    messages.forEach(function (message) {
                        showMessage(message.data, message.type, message.user, 0);
                    });
                };
            }

            // 页面加载完成后加载聊天记录
            window.onload = function () {
                loadMessages();
            };
        };
    </script>
</body>

</html>

node

var ws = require("nodejs-websocket")
var port = 8099;
var user = 0;
 
// 创建一个连接
var server = ws.createServer(function (conn) {
    console.log("创建一个新的连接--------");
    user++;
    // 给连接设置昵称属性
    conn.nickname = "user" + user;
    // 给连接设置文件描述符属性
    conn.fd = "user" + user;
    var mes = {};
    // 消息类型为进入聊天室
    mes.type = "enter";
    // 消息内容为进入提示
    mes.data = conn.nickname + " 进来啦";
    mes.state = 1;
    // 广播该消息给所有客户端
    broadcast(JSON.stringify(mes));
 
    //向客户端推送消息
    conn.on("text", function (str) {
        console.log("回复 " + str)
        // 消息类型为普通消息
        mes.type = "message";
        mes.user = conn.nickname + " 说:";
        mes.data = str;
        mes.state = 0;
        broadcast(JSON.stringify(mes));
    });
 
    //监听关闭连接操作
    conn.on("close", function (code, reason) {
        console.log("关闭连接");
        mes.type = "leave";
        mes.data = conn.nickname + " 离开了"
        broadcast(JSON.stringify(mes));
    });
 
    //错误处理
    conn.on("error", function (err) {
        console.log("监听到错误");
        console.log(err);
    });
}).listen(port);
 
function broadcast(str) {
    server.connections.forEach(function (connection) {
        connection.sendText(str);
    })
}

Guess you like

Origin blog.csdn.net/weixin_52479803/article/details/132337529