WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
讲人话就是说:WebSocket 使得客户端和服务器之间的数据交换变得更加简单,在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
WebSocket(url)
:创建WebSocket对象并与指定的URL建立连接- // 创建WebSocket对象并与服务器建立连接
- var socket = new WebSocket("ws://example.com");
send(data)
:向服务器发送数据- // 向服务器发送数据
- function sendData(data) {
- socket.send(data);
- console.log("发送数据:" + data);
- }
close(code, reason)
:主动关闭WebSocket连接- // 主动关闭WebSocket连接
- function closeConnection() {
- socket.close();
- console.log("关闭WebSocket连接");
- }
onopen
:当WebSocket连接成功打开时触发的事件- // 连接成功时触发的事件
- socket.onopen = function(event) {
- console.log("WebSocket连接已打开");
- // 发送数据示例
- socket.send("Hello, server!");
- };
onmessage
:当从服务器接收到消息时触发的事件- // 接收到消息时触发的事件
- socket.onmessage = function(event) {
- var message = event.data;
- console.log("收到消息:" + message);
- };
onclose
:当WebSocket连接关闭时触发的事件- // 连接关闭时触发的事件
- socket.onclose = function(event) {
- console.log("WebSocket连接已关闭");
- };
onerror
:当WebSocket连接发生错误时触发的事件- // 连接错误时触发的事件
- socket.onerror = function(error) {
- console.error("WebSocket错误:" + error);
- };
index.html
- <html>
- <head>
- <meta charset="UTF-8">
- <title>webrtc demotitle>
- 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 记得下载:nodejs-websocket依赖
- 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(索引数据库)是浏览器提供的一种客户端数据库存储解决方案。它允许 Web 应用程序在用户设备上存储大量结构化数据,并可在离线状态下进行查询和操作。IndexedDB 使用对象存储模型,类似于关系型数据库,但不支持 SQL 查询语言。
- 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");
- };
let objectStore = db.createObjectStore("messages", { keyPath: "id", autoIncrement: true });
objectStore.createIndex("type", "user", { unique: false });
let transaction = db.transaction(["messages"], "readwrite");
- 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");
- };
- let objectStore = transaction.objectStore("messages");
-
- let request = objectStore.get(1);
- request.onsuccess = function(event) {
- let data = event.target.result;
- console.log(data);
- };
- let objectStore = transaction.objectStore("messages");
-
- let request = objectStore.getAll();
- request.onsuccess = function(event) {
- let data = event.target.result;
- console.log(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");
- };
- let objectStore = transaction.objectStore("messages");
-
- let request = objectStore.delete(1);
- request.onsuccess = function(event) {
- console.log("Data deleted successfully");
- };
- let objectStore = transaction.objectStore("messages");
-
- let request = objectStore.clear();
- request.onsuccess = function(event) {
- console.log("Object store cleared successfully");
- };
WebSocket实现聊天,IndexedDB将聊天数据存储起来,防止刷新丢失
html
- DOCTYPE html>
- <html>
-
- <head>
- <meta charset="UTF-8">
- <title>webrtc demotitle>
- 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);
- })
- }