Socket.io 是什么,怎样利用,与 WebSocket 的关系?

打印 上一主题 下一主题

主题 854|帖子 854|积分 2562

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 提供了支持派发事件和监听时间的便捷功能,以下是官网案例:
  1. socket.emit("hello", "world", (response) => {
  2.   console.log(response); // "got it"
  3. });
  4. socket.on("hello", (arg, callback) => {
  5.   console.log(arg); // "world"
  6.   callback("got it");
  7. });
复制代码
上面代码中的"hello"就是双方约定好的事件,寻常项目开发中一般会在前面加上 $,表示自定义事件。


  • Socket.io 还提供了方便快捷的广播方式
  1. // socket.io
  2. io.on("connection", (socket) => {
  3.   socket.broadcast.emit("hello", "world");
  4. });
  5. // 原生 websocket
  6. socket.on('message', (message) => {
  7.   ws.clients.forEach((client) => {
  8.     client.send({
  9.       type: "hello",
  10.       message
  11.     });
  12.   })
  13. })
复制代码
利用 Socket.io 实现一个浅易聊天室



  • 我这里前端利用 vue3+TS,后端 node(这是肯定的,只支持node)
  • 先看成品展示,简朴做了一下,样式请不要在乎。。。


  • 以下是代码部门
  • 前端

    • html

  1. <template>
  2.   <div class="container">
  3.     <div class="users-area">
  4.       <!-- 待开发,感兴趣自己可以试着做做 -->
  5.       <input type="text" placeholder="搜索">
  6.       <ul class="users-list">
  7.         <li v-for="u in users" :key="u">{{ u }}</li>
  8.       </ul>
  9.     </div>
  10.     <div class="msg-area">
  11.       <div class="message-area">
  12.         <div class="item" :class="{ self: self === item.name }" v-for="(item, ind) in msgList" :key="ind">
  13.           <span class="name">{{ item.name }}</span>
  14.           <p class="message">{{ item.message }}</p>
  15.         </div>
  16.       </div>
  17.       <div class="input-area">
  18.         <textarea v-model="message" @keydown.enter="sendMsg"></textarea>
  19.       </div>
  20.     </div>
  21.   </div>
  22. </template>
复制代码


  • TS
  1. <script setup lang="ts">
  2. import { defineProps, watch, ref, defineEmits } from 'vue';
  3. const message = ref('');
  4. const emits = defineEmits(['chat'])
  5. type Props = {
  6.   users?: any[];
  7.   msgList?: { name: string, message: string}[];
  8.   self: string
  9. }
  10. const props = withDefaults(defineProps<Props>(), {
  11.   users: () => [],
  12.   msgList: () => []
  13. })
  14. const sendMsg = () => {
  15.   const val = message.value.trim();
  16.   if (val) {
  17.     message.value = '';
  18.     emits('chat', { name: props.self, message: val });
  19.   }
  20. }
  21. </script>
复制代码


  • CSS
  1. <style scoped>
  2. .container {
  3.   display: flex;
  4.   width: 550px;
  5.   height: 500px;
  6.   border-radius: 8px;
  7.   box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
  8.   background-color: rgb(235, 235, 235);
  9.   overflow: hidden;
  10. }
  11. .users-area {
  12.   width: 150px;
  13.   border-right: 1px solid #ccc;
  14.   line-height: 30px;
  15.   overflow: auto;
  16.   flex: 0 0 auto;
  17. }
  18. .users-area input {
  19.   margin-top: 10px;
  20.   width: 80%;
  21.   border: none
  22. }
  23. .users-area input:focus {
  24.   outline: 1px solid #aaa
  25. }
  26. .users-area p {
  27.   text-align: center;
  28.   border-bottom: 1px solid #ccc;
  29. }
  30. .users-area .users-list {
  31.   padding: 0;
  32.   margin: 10px 0;
  33.   list-style: none;
  34.   border-top: 1px solid #ccc;
  35. }
  36. .users-list li {
  37.   padding: 0 10px;
  38.   margin: 10px 0;
  39.   font-size: 12px;
  40.   border-bottom: 1px solid #ccc;
  41.   background: rgb(220, 220, 220);
  42. }
  43. .msg-area {
  44.   display: flex;
  45.   flex-direction: column;
  46.   flex: 1;
  47.   background-color: rgb(245, 245, 245);
  48. }
  49. .message-area {
  50.   height: 75%;
  51.   padding: 1em;
  52.   font-size: 14px;
  53.   line-height: 1.3;
  54.   overflow-y: scroll;
  55. }
  56. .item {
  57.   float: left;
  58.   max-width: 70%;
  59.   clear: both;
  60.   margin-bottom: 1em;
  61. }
  62. .name {
  63.   font-size: 12px;
  64.   color: #333;
  65. }
  66. .message {
  67.   border-radius: 6px;
  68.   padding: 10px;
  69.   margin: 4px 0;
  70.   background-color: #fff
  71. }
  72. .item.self {
  73.   float: right;
  74. }
  75. .self .message {
  76.   background-color: rgb(137, 217, 97);
  77. }
  78. .self .name {
  79.   text-align: right;
  80. }
  81. .input-area {
  82.   flex: 1;
  83.   border-top: 1px solid #ccc;
  84. }
  85. .input-area textarea {
  86.   width: 100%;
  87.   height: 100%;
  88.   padding: 10px 20px;
  89.   border: none;
  90.   outline: none;
  91. }
  92. </style>
复制代码


  • 上面是子组件(聊天框),以下是父组件逻辑
  1. <template>
  2.     <WeChat :self="self" :msgList="msgList" :users="users" @chat="handleChat" />
  3. </template>
  4.   
  5. <script setup lang='ts'>
  6. import WeChat from '@/components/WeChat.vue';
  7. import { io, Socket } from 'socket.io-client';
  8. import { ref, onMounted, onUnmounted } from 'vue';
  9. interface IChatContent {
  10.   name: string;
  11.   message: string
  12. }
  13. const msgList = ref<IChatContent[]>([]);
  14. const users = ref<string[]>([]);
  15. const self = ref('');
  16. const socket = ref<Socket | null>(null);
  17. onMounted(() => {
  18.   socket.value = io('http://localhost:3000');
  19.   // 接受消息
  20.   socket.value.on('$messages', (data: IChatContent) => {
  21.     msgList.value.push(data);
  22.   });
  23.   // 监听加入聊天室的用户
  24.   socket.value.on('$users', (data: string[]) => {
  25.     users.value = data;
  26.   });
  27.   // 监听其他人发送的消息
  28.   socket.value.on('$msgList', (data: IChatContent[]) => {
  29.     msgList.value = data;
  30.   });
  31. })
  32. const handleChat = (data: IChatContent) => {
  33.   msgList.value.push(data);
  34.   // 将当前聊天内容发送给服务器,通知其他人
  35.   (socket.value as Socket).emit('$messages', data.message);
  36. }
  37. /**
  38. * 组件卸载时断开连接
  39. */
  40. onUnmounted(() => {
  41.   (socket.value as Socket).disconnect();
  42. })
  43. </script>
复制代码


  • node 端
  1. import { Server } from "socket.io";
  2. const io = new Server({
  3.   path: '/',
  4.   cors: '*'
  5. });
  6. const usersList = []; // 用户集合
  7. const chatContentList = []; // 消息体集合
  8. let ind = 0; // 记录当前是第几位成员(做简单区分)
  9. io.on("connection", (socket) => {
  10.   const userName = '成员' + ++ind;
  11.   usersList.push(userName);
  12.   // 加入新成员并告知客户端(这里不能广播,因为广播不包括自己)
  13.   socket.emit('$users', usersList);
  14.   socket.on('$messages', (message) => {
  15.     const content = {
  16.       name: userName,
  17.       message
  18.     }
  19.     chatContentList.push(content);
  20.     // 给所有用户发送当前用户发来的消息
  21.     socket.broadcast.emit('$messages', content);
  22.   })
  23.   // 监听到连接关闭
  24.   socket.on('disconnect', () => {
  25.     // 清除用户
  26.     usersList.splice(usersList.indexOf(userName), 1);
  27.     // 广播通知所有用户
  28.     socket.broadcast.emit('$users', usersList);
  29.   });
  30. });
  31. io.listen(3000);
复制代码


  • 更多细节与功能请参考官网:https://socket.io/docs/v4/tutorial/introduction
  • 欢迎各位小伙伴指出意见,觉得不错的话不要忘记留下个赞哦,你的鼓励是我更新的动力,谢谢。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

我爱普洱茶

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表