什么是WebSocket?
WebSocket 是基于TCP/IP协议,独立于HTTP协议的通信协议。
WebSocket 是双向通讯,有状态,客户端一(多)个与服务端一(多)双向实时响应(客户端 ⇄ 服务端)。
WebSocket 是应用在浏览器的 Socket (是 Socket 模型接口的实现),Socket 是一个网络通信接口 (通信规范)。
WebSocket协议端口是80。
WebSocket SSL协议端口是443。
Socket是TCP/IP协议的网络数据通讯接口(一种底层的通讯的方式)。
Socket是IP地址和端口号的组合。例如:192.168.1.100:8080。
WebSocket的作用
通过一个长时的连接实现与服务器全双工、全双向的通信。
通俗的说 就是服务端与客户端建立连接,互相之间就确立了某种联系。客户端可以向服务端发送请求,然而服务端也可以向客户端发送请求
。打破了之前http连接状态下客户端只能向服务端发送请求的状况。
创建一个WebSocket时,一个Http服务以初始化连接。服务器响应后,链接使用的http头部从http协议切换到websocket协议(Upgrade)。
因为WebSocket使用了自定义协议,所以Url方案会有所改变,不能再使用http://, https://
需要使用ws://, wss://。前者是不安全的连接,后者是安全的连接。
使用自定义协议优点
客户端和服务端可以发送非常少的数据,不会对http造成任何负担。可以应用在带宽和延迟影响比较大的应用(数据包较小)。不受同源策略的影响
缺点
定义时间较长
使用WebSocket
创建
let ws = new WebSocket('ws://www.awdz.com/server.php');
通过new创建websocket,里面传入的url是绝对路径。因为不受同源策略的影响。所以可以打开任意站点的连接。
当初始化websocket后,浏览器会立即创建连接。
websocket也有一个readyState
值 | 状态 |
---|---|
WebSocket.opening(0) | 连接正在建立 |
WebSocket.open(1) | 连接已建立 |
WebSocket.closeing(2) | 连接正在关闭 |
WebSocket.close(3) | 连接已关闭 |
apis
api | 描述 |
---|---|
send | 发送给socket服务的数据 |
事件
event | 描述 |
---|---|
onopen | 在连接成功时触发 |
onerror | 在连接错误时触发 |
onclose | 在连接关闭时触发 |
onmessage | 在接收到服务响应数据时触发 |
关闭WebSocket的方法
.close()
方法
let ws = new WebSocket('wss://123.123.1.3:22/ww.txt');
// 关闭连接
ws.close();
发送请求到服务器,接收请求来自服务器
在服务器构建websocket服务(一个极其简陋的聊天室)
这里需要使用npm下载一个处理websocket服务的第三方模块
$ npm install nodejs-websocket -s
下载完成后引入模块
const socketConn = require('nodejs-websocket');
创建socket服务
const socketConnet = socket.createServer(conn => {
});
监听端口
socketConnet.listen(4400, err => {
if (err) {
throw new Error('socket启动失败');
}
console.log('socket启动成功');
});
监听socket状态
// 创建一个广播
socketConnet.connections.forEach(item => {
item.sendText('聊天室在线人数' + socketConnet.connections.length)
});
//监听socket的连接关闭
conn.on('close', () => {
console.log('连接关闭');
console.log(socketConnet.connections.length);
socketConnet.connections.forEach(item => {
item.sendText('聊天室在线人数' + socketConnet.connections.length)
});
});
// 接收来自客户端的请求
conn.on('text', (data) => {
conn.sendText('发挥作用' + JSON.parse(data));
})
// 监听连接的断开异常状态
conn.on('error', () => {
// console.log('err');
})
完整代码
const socket = require('nodejs-websocket');
const socketConnet = socket.createServer(conn => {
// 创建一个广播
socketConnet.connections.forEach(item => {
item.sendText(JSON.stringify({
key: 001, value: '聊天室在线人数' + socketConnet.connections.length
}))
});
//监听socket的连接关闭
conn.on('close', () => {
socketConnet.connections.forEach(item => {
item.sendText(JSON.stringify({
key: 001, value: '聊天室在线人数' + socketConnet.connections.length
}))
});
});
// 接收来自客户端的请求
conn.on('text', (data) => {
let userData = {
key: conn.key,
value: data
}
// 广播分发
socketConnet.connections.forEach(item => {
item.sendText(JSON.stringify(userData));
});
})
// 监听连接的断开异常状态
conn.on('error', () => {
})
});
// 监听端口
socketConnet.listen(3300, err => {
if (err) {
throw new Error('socket启动失败');
}
console.log('socket启动成功');
});
在客户端使用webSocket
创建websocket服务
let socket = new WebSocket('ws://localhost:4400');
事件
// 创建websocket
let socket = new WebSocket('ws://192.168.2.97:3300');
let chatRoom = document.querySelector('.chatRoom');
let input = document.querySelector('input');
let ul = document.querySelector('ul');
// socket连接成功时触发
socket.onopen = function () {
console.log('连接成功');
}
// socket连接关闭时触发
socket.onclose = function () {
console.log('连接断开');
}
// socket连接失败时触发
socket.onerror = function (err) {
console.log('连接失败' + err);
// 失败时关闭连接
socket.close();
}
// 接收socket服务器的响应或者请求
socket.onmessage = function (message) {
// console.log(message);
if (message && JSON.parse(message.data).key) {
if (JSON.parse(message.data).key === 1) {
chatRoom.innerText = JSON.parse(message.data).value;
} else {
let li = document.createElement('li');
li.innerHTML = `
<div class="name">${JSON.parse(message.data).key}</div>
<p>${JSON.parse(message.data).value}</p>
`;
ul.appendChild(li);
}
} else {
}
}
let buttons = document.querySelectorAll('button');
buttons[0].onclick = function () {
if (input.value.trim()) {
socket.send(input.value);
input.value = ''
} else {
confirm('输入不能为空!');
}
}
buttons[1].onclick = function () {
socket.close();
confirm('已断开链接');
}
close方法可关闭socket连接
全部代码
<!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>
* {
margin: 0;
padding: 0;
}
.phone {
width: 300px;
height: 600px;
padding: 20px;
margin: 0 auto;
border-radius: 10px;
border: 1px solid #ff0;
}
div.show {
position: relative;
width: 300px;
height: 560px;
border-radius: 10px;
border: 1px solid #111;
}
p.chatRoom {
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
border-radius: 10px;
background-color: rgba(255, 255, 0, 0.473);
}
.kuang {
width: 100%;
overflow-y: auto;
height: calc(100% - 80px);
}
ul {
width: 100%;
}
li {
width: 100%;
min-height: 60px;
margin-bottom: 10px;
background-color: rgb(247, 245, 245);
}
.name {
width: 100%;
height: 20px;
color: red;
}
li>p {
width: calc(100%-20px);
padding: 0 10px;
min-height: 40px;
border: 1px solid #ccc;
word-wrap: break-word;
}
input {
position: absolute;
bottom: 0;
width: 200px;
height: 30px;
}
</style>
</head>
<body>
<div class="phone">
<div class="show">
<p class="chatRoom">
</p>
<div class="kuang">
<ul>
</ul>
</div>
<input type="text">
</div>
<button>发送消息</button>
<button>关闭websocket</button>
</div>
<script>
// 创建websocket
let socket = new WebSocket('ws://192.168.2.97:3300');
let chatRoom = document.querySelector('.chatRoom');
let input = document.querySelector('input');
let ul = document.querySelector('ul');
// socket连接成功时触发
socket.onopen = function () {
console.log('连接成功');
}
// socket连接关闭时触发
socket.onclose = function () {
console.log('连接断开');
}
// socket连接失败时触发
socket.onerror = function (err) {
console.log('连接失败' + err);
// 失败时关闭连接
socket.close();
}
// 接收socket服务器的响应或者请求
socket.onmessage = function (message) {
// console.log(message);
if (message && JSON.parse(message.data).key) {
if (JSON.parse(message.data).key === 1) {
chatRoom.innerText = JSON.parse(message.data).value;
} else {
let li = document.createElement('li');
li.innerHTML = `
<div class="name">${JSON.parse(message.data).key}</div>
<p>${JSON.parse(message.data).value}</p>
`;
ul.appendChild(li);
}
} else {
}
}
let buttons = document.querySelectorAll('button');
buttons[0].onclick = function () {
if (input.value.trim()) {
socket.send(input.value);
input.value = ''
} else {
confirm('输入不能为空!');
}
}
buttons[1].onclick = function () {
socket.close();
confirm('已断开链接');
}
</script>
</body>
</html>
挂载静态页面
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
app.get('/', (request, response) => {
fs.readFile(path.join(__dirname + '/public/index.html'), (err, data) => {
if (err) {
response.end('<h1>404~</h1>');
return;
}
response.end(data);
});
});
app.listen(4400, err => {
if (err) {
console.log(err);
return;
}
console.log('启动服务成功');
});