Socket.io 是什么,如何使用,与 WebSocket 的关系?
介绍
上篇我们讲到了 WebSocket 的使用,不太了解的小伙伴,建议先到我上篇文章了解下再来学习。
Socket.io是一个建立在 WebSocket 协议之上的库,他提供了低延迟、双向通信、基于事件(可以自定义双方约定好的事件)的功能,保证了使用中的稳定性和兼容性,比如用户使用的浏览器版本不支持,会使用 HTTP长轮询 实现:断线自动重连的功能。
与 WebSocket 区别
- Socket.io 虽然建立在 WebSocket 协议之上,但不是 WebSocket 的实现。
- 目前仍有些许浏览器无法建立WebSocket连接,使用 Socket.io 可以做兼容性处理,转为 HTTP长轮询。
- 服务器和客户端之间的WebSocket连接可能会中断,双方都不知道连接的中断状态。Socket.io 自带一个心跳机制,它可以定期检查连接的状态,WebSocket 需要手动实现。
- 虽然 Socket.io 确实是在客户端支持的情况下使用 WebSocket 进行传输,但是它为每个数据包添加了额外的 元数据。这就是 WebSocket 客户端无法成功连接到 Socket.io 服务端,Socket.io 客户端也无法连接到普通的WebSocket服务器的原因。所以双方要同时规定好使用 websocket 还是 Socket.io,不能混用。
- Socket.io 提供了支持派发事件和监听时间的便捷功能,以下是官网案例:
socket.emit("hello","world",(response)=>{
console.log(response);// "got it"});
socket.on("hello",(arg, callback)=>{
console.log(arg);// "world"callback("got it");});
上面代码中的"hello"就是双方约定好的事件,平常项目开发中一般会在前面加上 $,表示自定义事件。
- Socket.io 还提供了方便快捷的广播方式
// socket.io
io.on("connection",(socket)=>{
socket.broadcast.emit("hello","world");});// 原生 websocket
socket.on('message',(message)=>{
ws.clients.forEach((client)=>{
client.send({type:"hello",
message
});})})
使用 Socket.io 实现一个简易聊天室
- 我这里前端使用 vue3+TS,后端 node(这是肯定的,只支持node)
- 先看成品展示,简单做了一下,样式请不要在乎。。。
- 以下是代码部分
- 前端- html
<template><divclass="container"><divclass="users-area"><!-- 待开发,感兴趣自己可以试着做做 --><inputtype="text"placeholder="搜索"><ulclass="users-list"><liv-for="u in users":key="u">{{ u }}</li></ul></div><divclass="msg-area"><divclass="message-area"><divclass="item":class="{ self: self === item.name }"v-for="(item, ind) in msgList":key="ind"><spanclass="name">{{ item.name }}</span><pclass="message">{{ item.message }}</p></div></div><divclass="input-area"><textareav-model="message"@keydown.enter="sendMsg"></textarea></div></div></div></template>
- TS
<script setup lang="ts">import{ defineProps, watch, ref, defineEmits }from'vue';const message =ref('');const emits =defineEmits(['chat'])typeProps={
users?:any[];
msgList?:{ name:string, message:string}[];
self:string}const props =withDefaults(defineProps<Props>(),{users:()=>[],msgList:()=>[]})constsendMsg=()=>{const val = message.value.trim();if(val){
message.value ='';emits('chat',{ name: props.self, message: val });}}</script>
- CSS
<style scoped>
.container{display: flex;width: 550px;height: 500px;border-radius: 8px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);background-color:rgb(235, 235, 235);overflow: hidden;}.users-area{width: 150px;border-right: 1px solid #ccc;line-height: 30px;overflow: auto;flex: 0 0 auto;}.users-area input{margin-top: 10px;width: 80%;border: none
}.users-area input:focus{outline: 1px solid #aaa
}.users-area p{text-align: center;border-bottom: 1px solid #ccc;}.users-area .users-list{padding: 0;margin: 10px 0;list-style: none;border-top: 1px solid #ccc;}.users-list li{padding: 0 10px;margin: 10px 0;font-size: 12px;border-bottom: 1px solid #ccc;background:rgb(220, 220, 220);}.msg-area{display: flex;flex-direction: column;flex: 1;background-color:rgb(245, 245, 245);}.message-area{height: 75%;padding: 1em;font-size: 14px;line-height: 1.3;overflow-y: scroll;}.item{float: left;max-width: 70%;clear: both;margin-bottom: 1em;}.name{font-size: 12px;color: #333;}.message{border-radius: 6px;padding: 10px;margin: 4px 0;background-color: #fff
}.item.self{float: right;}.self .message{background-color:rgb(137, 217, 97);}.self .name{text-align: right;}.input-area{flex: 1;border-top: 1px solid #ccc;}.input-area textarea{width: 100%;height: 100%;padding: 10px 20px;border: none;outline: none;}
</style>
- 上面是子组件(聊天框),以下是父组件逻辑
<template><WeChat :self="self":msgList="msgList":users="users"@chat="handleChat"/></template><script setup lang='ts'>import WeChat from'@/components/WeChat.vue';import{ io, Socket }from'socket.io-client';import{ ref, onMounted, onUnmounted }from'vue';interfaceIChatContent{
name:string;
message:string}const msgList =ref<IChatContent[]>([]);const users =ref<string[]>([]);const self =ref('');const socket =ref<Socket |null>(null);onMounted(()=>{
socket.value =io('http://localhost:3000');// 接受消息
socket.value.on('$messages',(data: IChatContent)=>{
msgList.value.push(data);});// 监听加入聊天室的用户
socket.value.on('$users',(data:string[])=>{
users.value = data;});// 监听其他人发送的消息
socket.value.on('$msgList',(data: IChatContent[])=>{
msgList.value = data;});})consthandleChat=(data: IChatContent)=>{
msgList.value.push(data);// 将当前聊天内容发送给服务器,通知其他人(socket.value as Socket).emit('$messages', data.message);}/**
* 组件卸载时断开连接
*/onUnmounted(()=>{(socket.value as Socket).disconnect();})</script>
- node 端
import{ Server }from"socket.io";const io =newServer({path:'/',cors:'*'});const usersList =[];// 用户集合const chatContentList =[];// 消息体集合let ind =0;// 记录当前是第几位成员(做简单区分)
io.on("connection",(socket)=>{const userName ='成员'+++ind;
usersList.push(userName);// 加入新成员并告知客户端(这里不能广播,因为广播不包括自己)
socket.emit('$users', usersList);
socket.on('$messages',(message)=>{const content ={name: userName,
message
}
chatContentList.push(content);// 给所有用户发送当前用户发来的消息
socket.broadcast.emit('$messages', content);})// 监听到连接关闭
socket.on('disconnect',()=>{// 清除用户
usersList.splice(usersList.indexOf(userName),1);// 广播通知所有用户
socket.broadcast.emit('$users', usersList);});});
io.listen(3000);
- 更多细节与功能请参考官网:https://socket.io/docs/v4/tutorial/introduction
- 欢迎各位小伙伴指出意见,觉得不错的话不要忘记留下个赞哦,你的鼓励是我更新的动力,谢谢。
版权归原作者 Liquor~~ 所有, 如有侵权,请联系我们删除。