• 【WebSocket&IndexedDB】node+WebSocket&IndexedDB开发简易聊天室


    序幕介绍:

    WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

    讲人话就是说:WebSocket 使得客户端和服务器之间的数据交换变得更加简单,在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输

    现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

    HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

    WebSocket:

    • 常见方法WebSocket(url):创建WebSocket对象并与指定的URL建立连接
    1. // 创建WebSocket对象并与服务器建立连接
    2. var socket = new WebSocket("ws://example.com");
    • 常见方法send(data):向服务器发送数据
    1. // 向服务器发送数据
    2. function sendData(data) {
    3. socket.send(data);
    4. console.log("发送数据:" + data);
    5. }
    • 常见方法close(code, reason):主动关闭WebSocket连接
    1. // 主动关闭WebSocket连接
    2. function closeConnection() {
    3. socket.close();
    4. console.log("关闭WebSocket连接");
    5. }
    • 常见事件:onopen:当WebSocket连接成功打开时触发的事件
    1. // 连接成功时触发的事件
    2. socket.onopen = function(event) {
    3. console.log("WebSocket连接已打开");
    4. // 发送数据示例
    5. socket.send("Hello, server!");
    6. };
    • 常见事件:onmessage:当从服务器接收到消息时触发的事件
    1. // 接收到消息时触发的事件
    2. socket.onmessage = function(event) {
    3. var message = event.data;
    4. console.log("收到消息:" + message);
    5. };
    • 常见事件:onclose:当WebSocket连接关闭时触发的事件
    1. // 连接关闭时触发的事件
    2. socket.onclose = function(event) {
    3. console.log("WebSocket连接已关闭");
    4. };
    • 常见事件: onerror:当WebSocket连接发生错误时触发的事件
    1. // 连接错误时触发的事件
    2. socket.onerror = function(error) {
    3. console.error("WebSocket错误:" + error);
    4. };

    效果图:

    代码展示:

    index.html

    1. <html>
    2. <head>
    3. <meta charset="UTF-8">
    4. <title>webrtc demotitle>
    5. head>
    6. <body>
    7. <h1>Websocket简易聊天h1>
    8. <div id="app">
    9. <input id="sendMsg" type="text" />
    10. <button id="submitBtn">发送button>
    11. div>
    12. body>
    13. <script type="text/javascript">
    14. //在页面显示聊天内容
    15. function showMessage(str, type) {
    16. var div = document.createElement("div");
    17. div.innerHTML = str;
    18. if (type == "enter") {
    19. div.style.color = "blue";
    20. } else if (type == "leave") {
    21. div.style.color = "red";
    22. }
    23. document.body.appendChild(div);
    24. }
    25. //新建一个websocket
    26. var websocket = new WebSocket("ws://172.21.2.52:8099");
    27. //连接建立时触发
    28. websocket.onopen = function () {
    29. console.log("已经连上服务器----");
    30. document.getElementById("submitBtn").onclick = function () {
    31. // 获取输入的内容
    32. var txt = document.getElementById("sendMsg").value;
    33. if (txt) {
    34. //使用连接发送数据
    35. websocket.send(txt);
    36. }
    37. };
    38. };
    39. //连接关闭时触发
    40. websocket.onclose = function () {
    41. console.log("websocket close");
    42. };
    43. //客户端接收服务端数据时触发
    44. websocket.onmessage = function (e) {
    45. var mes = JSON.parse(e.data); // json格式
    46. // 渲染
    47. showMessage(mes.data, mes.type);
    48. };
    49. script>
    50. html>

    node.js    记得下载:nodejs-websocket依赖

    1. var ws = require("nodejs-websocket")
    2. var port = 8099;
    3. var user = 0;
    4. // 创建一个连接
    5. var server = ws.createServer(function (conn) {
    6. console.log("创建一个新的连接--------");
    7. user++;
    8. // 给连接设置昵称属性
    9. conn.nickname = "user" + user;
    10. // 给连接设置文件描述符属性
    11. conn.fd = "user" + user;
    12. var mes = {};
    13. // 消息类型为进入聊天室
    14. mes.type = "enter";
    15. // 消息内容为进入提示
    16. mes.data = conn.nickname + " 进来啦"
    17. // 广播该消息给所有客户端
    18. broadcast(JSON.stringify(mes));
    19. //向客户端推送消息
    20. conn.on("text", function (str) {
    21. console.log("回复 " + str)
    22. // 消息类型为普通消息
    23. mes.type = "message";
    24. mes.data = conn.nickname + " 说: " + str;
    25. broadcast(JSON.stringify(mes));
    26. });
    27. //监听关闭连接操作
    28. conn.on("close", function (code, reason) {
    29. console.log("关闭连接");
    30. mes.type = "leave";
    31. mes.data = conn.nickname + " 离开了"
    32. broadcast(JSON.stringify(mes));
    33. });
    34. //错误处理
    35. conn.on("error", function (err) {
    36. console.log("监听到错误");
    37. console.log(err);
    38. });
    39. }).listen(port);
    40. function broadcast(str) {
    41. server.connections.forEach(function (connection) {
    42. connection.sendText(str);
    43. })
    44. }

    IndexedDB

    IndexedDB(索引数据库)是浏览器提供的一种客户端数据库存储解决方案。它允许 Web 应用程序在用户设备上存储大量结构化数据,并可在离线状态下进行查询和操作。IndexedDB 使用对象存储模型,类似于关系型数据库,但不支持 SQL 查询语言。

    • open(): 打开数据库连接
    1. let request = window.indexedDB.open("myDatabase", 1);
    2. request.onerror = function(event) {
    3. console.log("Failed to open database");
    4. };
    5. request.onsuccess = function(event) {
    6. let db = event.target.result;
    7. console.log("Database opened successfully");
    8. };
    • createObjectStore(): 创建对象存储空间
    let objectStore = db.createObjectStore("messages", { keyPath: "id", autoIncrement: true });
    
    • createIndex(): 创建索引
    objectStore.createIndex("type", "user", { unique: false });
    
    • transaction(): 开启事务
    let transaction = db.transaction(["messages"], "readwrite");
    
    • objectStore.add(): 添加数据到对象存储空间
    1. let objectStore = transaction.objectStore("messages");
    2. let message = { id: 1, type: "text", data: "Hello World", user: "Alice" };
    3. let request = objectStore.add(message);
    4. request.onsuccess = function(event) {
    5. console.log("Data added successfully");
    6. };
    • objectStore.get(): 通过主键获取数据
    1. let objectStore = transaction.objectStore("messages");
    2. let request = objectStore.get(1);
    3. request.onsuccess = function(event) {
    4. let data = event.target.result;
    5. console.log(data);
    6. };
    • objectStore.getAll(): 获取所有数据
    1. let objectStore = transaction.objectStore("messages");
    2. let request = objectStore.getAll();
    3. request.onsuccess = function(event) {
    4. let data = event.target.result;
    5. console.log(data);
    6. };
    • objectStore.put(): 更新数据
    1. let objectStore = transaction.objectStore("messages");
    2. let message = { id: 1, type: "text", data: "Hello Updated", user: "Alice" };
    3. let request = objectStore.put(message);
    4. request.onsuccess = function(event) {
    5. console.log("Data updated successfully");
    6. };
    • objectStore.delete(): 删除数据
    1. let objectStore = transaction.objectStore("messages");
    2. let request = objectStore.delete(1);
    3. request.onsuccess = function(event) {
    4. console.log("Data deleted successfully");
    5. };
    • clear(): 清空对象存储空间中的所有数据
    1. let objectStore = transaction.objectStore("messages");
    2. let request = objectStore.clear();
    3. request.onsuccess = function(event) {
    4. console.log("Object store cleared successfully");
    5. };

    WebSocket加IndexedDB完整代码

    WebSocket实现聊天,IndexedDB将聊天数据存储起来,防止刷新丢失

    html

    1. DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>webrtc demotitle>
    6. head>
    7. <body>
    8. <h1>Websocket简易聊天h1>
    9. <div id="app">
    10. <input id="sendMsg" type="text" />
    11. <button id="submitBtn">发送button>
    12. <div id="leaveMessage">div>
    13. <div id="chat">div>
    14. div>
    15. <script type="text/javascript">
    16. var db, transaction, objectStore;
    17. // 在页面显示聊天内容
    18. function showMessage(str, type, user = null, state = 1) {
    19. var div = document.createElement("div");
    20. var spanStr = document.createElement("span");
    21. spanStr.innerHTML = str;
    22. if (user != null) {
    23. var spanUser = document.createElement("span");
    24. spanUser.innerHTML = user;
    25. div.appendChild(spanUser);
    26. }
    27. if (type == "enter") {
    28. div.style.color = "blue";
    29. } else if (type == "leave") {
    30. div.style.color = "red";
    31. }
    32. div.appendChild(spanStr);
    33. document.getElementById("chat").appendChild(div);
    34. if (state == 1) {
    35. document.getElementById("chat").appendChild(div);
    36. } else {
    37. document.getElementById("leaveMessage").appendChild(div);
    38. }
    39. }
    40. // 创建或打开 IndexedDB 数据库
    41. var request = window.indexedDB.open("chatDB", 1);
    42. request.onerror = function () {
    43. console.log("无法打开数据库");
    44. };
    45. request.onupgradeneeded = function (event) {
    46. // 获取到数据库对象 db
    47. db = event.target.result;
    48. // 创建名为 "messages" 的对象存储,并指定 "id" 为键路径,并自动递增生成
    49. objectStore = db.createObjectStore("messages", { keyPath: "id", autoIncrement: true });
    50. // 创建一个名为 "type" 的索引,用于根据消息类型进行检索,允许重复值
    51. objectStore.createIndex("type", "user", { unique: false });
    52. // 创建一个名为 "data" 的索引,用于根据消息内容进行检索,允许重复值
    53. objectStore.createIndex("data", "data", { unique: false });
    54. objectStore.createIndex("state", "state", { unique: false });
    55. objectStore.createIndex("user", "user", { unique: false });
    56. };
    57. request.onsuccess = function (event) {
    58. db = event.target.result;
    59. // 新建一个websocket
    60. var websocket = new WebSocket("ws://172.21.2.52:8099");
    61. // 连接建立时触发
    62. websocket.onopen = function () {
    63. console.log("已经连上服务器----");
    64. document.getElementById("submitBtn").onclick = function () {
    65. var txt = document.getElementById("sendMsg").value;
    66. if (txt) {
    67. websocket.send(JSON.stringify(txt));
    68. }
    69. };
    70. // 给输入框添加键盘按下事件监听器
    71. document.getElementById("sendMsg").addEventListener("keydown", function (event) {
    72. // 检查按下的键是否是回车键(键码为13)
    73. if (event.keyCode == 13) {
    74. // 取消回车键的默认行为(避免表单提交等操作)
    75. event.preventDefault();
    76. var txt = document.getElementById("sendMsg").value;
    77. if (txt) {
    78. websocket.send(JSON.stringify(txt));
    79. }
    80. }
    81. });
    82. };
    83. // 连接关闭时触发
    84. websocket.onclose = function () {
    85. console.log("websocket close");
    86. };
    87. // 客户端接收服务端数据时触发
    88. websocket.onmessage = function (e) {
    89. var mes = JSON.parse(e.data); // json格式
    90. // 渲染
    91. if (mes.state == 0) {
    92. showMessage(mes.data, mes.type, mes.user);
    93. saveMessage(mes)
    94. document.getElementById("sendMsg").value = ''
    95. } else {
    96. showMessage(mes.data, mes.type);
    97. }
    98. };
    99. function saveMessage(message) {
    100. let transaction = db.transaction(["messages"], "readwrite");
    101. let objectStore = transaction.objectStore("messages");
    102. var saveRequest = objectStore.add(message);
    103. saveRequest.onsuccess = function () {
    104. console.log("消息已保存到 IndexedDB");
    105. };
    106. saveRequest.onerror = function () {
    107. console.log("保存消息时发生错误");
    108. };
    109. }
    110. function loadMessages() {
    111. // 创建一个只读事务,该事务用于操作名为 "messages" 的对象存储
    112. transaction = db.transaction(["messages"], "readonly");
    113. // 获取对 "messages" 对象存储的引用,以便进行后续的操作
    114. objectStore = transaction.objectStore("messages");
    115. // 回一个获取所有数据的请求
    116. var getAllRequest = objectStore.getAll();
    117. // 在获取数据成功时触发
    118. getAllRequest.onsuccess = function () {
    119. var messages = getAllRequest.result;
    120. messages.forEach(function (message) {
    121. showMessage(message.data, message.type, message.user, 0);
    122. });
    123. };
    124. }
    125. // 页面加载完成后加载聊天记录
    126. window.onload = function () {
    127. loadMessages();
    128. };
    129. };
    130. script>
    131. body>
    132. html>

    node

    1. var ws = require("nodejs-websocket")
    2. var port = 8099;
    3. var user = 0;
    4. // 创建一个连接
    5. var server = ws.createServer(function (conn) {
    6. console.log("创建一个新的连接--------");
    7. user++;
    8. // 给连接设置昵称属性
    9. conn.nickname = "user" + user;
    10. // 给连接设置文件描述符属性
    11. conn.fd = "user" + user;
    12. var mes = {};
    13. // 消息类型为进入聊天室
    14. mes.type = "enter";
    15. // 消息内容为进入提示
    16. mes.data = conn.nickname + " 进来啦";
    17. mes.state = 1;
    18. // 广播该消息给所有客户端
    19. broadcast(JSON.stringify(mes));
    20. //向客户端推送消息
    21. conn.on("text", function (str) {
    22. console.log("回复 " + str)
    23. // 消息类型为普通消息
    24. mes.type = "message";
    25. mes.user = conn.nickname + " 说:";
    26. mes.data = str;
    27. mes.state = 0;
    28. broadcast(JSON.stringify(mes));
    29. });
    30. //监听关闭连接操作
    31. conn.on("close", function (code, reason) {
    32. console.log("关闭连接");
    33. mes.type = "leave";
    34. mes.data = conn.nickname + " 离开了"
    35. broadcast(JSON.stringify(mes));
    36. });
    37. //错误处理
    38. conn.on("error", function (err) {
    39. console.log("监听到错误");
    40. console.log(err);
    41. });
    42. }).listen(port);
    43. function broadcast(str) {
    44. server.connections.forEach(function (connection) {
    45. connection.sendText(str);
    46. })
    47. }

  • 相关阅读:
    四、概率论
    招投标系统简介 企业电子招投标采购系统源码之电子招投标系统 —降低企业采购成本
    JAVA计算机毕业设计沧州雄狮足球俱乐部管理系统Mybatis+源码+数据库+lw文档+系统+调试部署
    Git工具的使用
    MySQL——子查询和嵌套查询
    moodle4.04无法上传中文文件名
    ELK Springboot集成ElasticSearch7.6.2 SpringData
    最全面的Spring教程(五)——文件上传与下载
    【云原生】-Docker部署及使用压测神器sysbench
    ubuntu 安装harbor
  • 原文地址:https://blog.csdn.net/weixin_52479803/article/details/132337529