HTTP
HTTP是客户端和服务器之间进行请求与响应所用的协议,在这种模式中,浏览器向服务器发送HTTP请求,服务器收到请求并响应给浏览器请求的资源。但是我们也要知道,HTTP是半双工通信,也就是(特点):
- 同一时刻数据是单向流动的,客户端向服务端请求数据是单向,服务端向客户端响应返回数据也是单向;
- 服务器不能主动的响应数据给客户端。
HTTP的三次握手与四次挥手
随便说一下HTTP的三次握手与四次挥手,都是自己总结的。
三次握手:
第一次:客户端—>发送SYN数据包(在吗?)—>服务端
第二次:服务端—>响应SYN与ACK确认包(在呢,咋啦?)—>客户端
第三次:客户端—>发送ACK确认(我给你说我今天.....)—>服务端
四次挥手:
第一次:客户端—>发送FIN用于关闭数据传送(我数据传送完了,我关闭连接了)—>服务端
第二次:服务端—>响应ACK确定,序号为收到序号加1(好的,我看看我还有没有需要传送的数据)—>客户端
第三次:服务端—>关闭连接,并响应FIN(没有啦,关闭连接吧)—>客户端
第四次:客户端—>发送ACK确定,序号为收到序号加1(好的,我关闭了)—>服务端
WebSocket
WebSocket实现了双工通信,就是在客户端和服务端上建立一个长久的连接,然后两边可以任意发送数据,它属于应用层的协议,基于TCP传输协议并复用HTTP的握手通道。
WebSocket的优势:
- 支持双向通信,实时性更强;
- 更好的二进制支持;
- 较少的控制开销(连接创建后,ws客户端与服务端数据交换时,协议控制的数据包头部较少)。
实现一个聊天Demo:
serve端:
const Ws = require('ws')
; (() => {
// 端口4000
const server = new Ws.Server({ port: 4000 })
// 初始化函数
const init = () => {
bindEvent()
}
// 事件函数
function bindEvent () {
// 用 server.on()书写服务端事件函数
server.on('open', handleOpen)
server.on('close', handleClose)
server.on('error', handleError)
server.on('connection', handleConnection)
}
function handleOpen () {
console.log('open');
}
function handleClose () {
console.log('close');
}
function handleError () {
console.log('error');
}
function handleConnection (ws) {
// 服务端建立连接后,会在建立连接的函数里面绑定信息处理函数
ws.on('message', handleMessage)
console.log('connection');
}
function handleMessage (msg) {
console.log('message', msg);
// 服务端监听客户端
server.clients.forEach(function (c) {
c.send(msg)
})
}
init()
})()
客户端:
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>
</head>
<body>
<ul id="list"></ul>
<input type="text" id="message" placeholder="请输入消息">
<button id="send">发送</button>
<script src="./js//index.js"></script>
</body>
</html>
index.js
; ((doc, Socket) => {
// 获取元素
const oList = doc.querySelector('#list')
const oMsg = doc.querySelector('#message')
const oBtn = doc.querySelector('#send')
// 实例化ws,设置端口和服务端端口号一致
const ws = new Socket('ws:localhost:4000')
let username = ''
// 初始化函数
const init = () => {
bindEvent()
}
// 事件函数
function bindEvent () {
// 发送点击事件
oBtn.addEventListener('click', handleSendBtnClick, false)
// ws绑定事件函数
ws.addEventListener('open', handleOpen, false)
ws.addEventListener('close', handleClose, false)
ws.addEventListener('error', handleError, false)
ws.addEventListener('message', handleMessage, false)
}
function handleSendBtnClick () {
console.log('send');
const msg = oMsg.value
if (!msg.trim().length) {
return
}
// 发送信息给服务端,要用JSON格式的数据
ws.send(JSON.stringify({
user: username,
dateTime: new Date().getTime(),
message: msg
}))
}
function handleOpen (e) {
console.log('open', e);
// 如果有写登录需要带参请求的先本地获取
username = localStorage.getItem('username')
if (!username) {
location.href('entry.html')
return
}
}
function handleClose (e) {
console.log('close', e);
}
function handleError (e) {
console.log('error', e);
}
// 拿到服务端响应的数据
function handleMessage (e) {
console.log(e.data);
console.log(JSON.parse(e.data));
const msgData = JSON.parse(e.data)
oList.appendChild(createMsg(msgData))
}
// 根据拿到的数据渲染元素
function createMsg (data) {
const { user, dateTime, message } = data
const oItem = doc.createElement('li')
oItem.innerHTML = `
<p>
<span>${user}</span>
<i>${new Date(dateTime)}</i>
</p>
<P>${message}</P>
`
return oItem
}
init()
})(document, WebSocket)
如果有兴趣可以学习一下封装库 socket.io,由于WebSocket是H5标准出的东西,所以对老版本的浏览器不能很好的支持,而 socket.io 可以很好的处理这些。后面有机会会继续补充~