最好的数据通信协议—WebSocket

396 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

WebSocket是什么?

WebSocket 是一种数据通信协议,类似于我们常见的 http 协议。

初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?

答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起。http基于请求响应实现。

举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。

这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用轮询:每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。但是轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。

image.png

websocket简介

WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

典型的websocket应用场景:

  • 即时通讯.....客服
  • 聊天室 广播
  • 点餐

socket技术

1、 客户端:发socket请求

0.  可以用原生的
0.  可以使用包 **socket.io**

2、. 服务器端: 提供socket服务

0.  **socket.io**

基本流程

image.png

WebSocket的使用

1、下载socket.io-client包

npm i socket.io-client

2、服务器建立链接

import io from 'socket.io-client'
// 和服务器建立了链接
 const client = io('地址', {
query: {
    token: 用户token
},
transports: ['websocket']
})

3、服务器进行通讯

// connect, disconnect 是固定的名字
client.on('connect', () => {  })  // 当和服务器建立连接成功,这个事件就会触发
client.on('disconnect', () => {})    // 和服务器断开链接,就会触发disconnect

// message是事件名,这个可以由后端去修改
// 接收到服务器的消息
client.on('message', () => {})  // 接收到服务器的消息,这个事件就会触发

// 主动给服务器发送消息
client.emit('message', 值)


// 主动关闭和服务器的链接
client.close()

示例写一个聊天机器人小项目练习使用Websocket

1、安装 socket.io 客户端库:socket.io-client

npm i socket.io-client

2、在进入机器人页面时,创建 socket.io 客户端

import io from 'socket.io-client'
import { getToken } from '@/utils/storage'

//定义聊天记录
const [messageList, setMessageList] = useState<
{type: 'robot' | 'user'text: string}[]>([
{ type: 'robot', text: '亲爱的用户您好,小智同学为您服务。' },
{ type: 'user', text: '你好' }
])

// 用于缓存 socket.io 客户端实例
const clientRef = useRef<Socket | null>(null)

//借助uesEffect的副作用,完成已进入页面就创建客户端
useEffect(() => {
// 创建客户端实例
const client = io('http://#########', {
transports: ['websocket'],
// 在查询字符串参数中传递 token
query: {
  token: getToken().token
}
})

// 监听连接成功的事件
client.on('connect', () => {
// 向聊天记录中添加一条消息
setMessageList(messageList => [
  ...messageList,
  { type: 'robot', text: '我现在恭候着您的提问。' }
])
})

// 监听收到消息的事件
client.on('message', data => {
console.log('>>>>收到 socket.io 消息:', data)
})

// 将客户端实例缓存到 ref 引用中,这样可以在外面使用client
clientRef.current = client

// 在组件销毁时关闭 socket.io 的连接
return () => {
client.close()
}
}, [])

给机器人发消息、使用 socket.io 实例的 emit() 方法发送信息

1、声明一个状态,并绑定消息输入框

// 输入框中的内容
const [message, setMessage] = useState('')

<Input
className="no-border"
placeholder="请描述您的问题"
value={message}
onChange={e => setMessage(e)}
 />

2、为消息输入框添加键盘事件,在输入回车时发送消息

<Input onKeyUp={onSendMessage}/>
// 按发送消息
const onSendMessage = () => {
console.log(value)
if (value.trim() === '') {
  return
}

// 1. 发消息
ioRef.current?.emit('message', { msg: value, timestamp: Date.now() })
// 2. 添加到聊天记录
setMessageList([...messageList, { type: 'user', text: value }])

// 3. 清空
setValue('')
}

接收机器人回复的消息

通过 socket.io 监听回复的消息,并添加到聊天列表中,给socket.io 实例监听 message 事件,在事件回调中接收信息,添加状态

// 监听收到消息的事件
client.on('message', (data) => {
// 向聊天记录中添加机器人回复的消息
setMessageList((messageList) => [
...messageList,
{ type: 'robot', text: data.msg },
])
})