SocketIo的使用和基于SocketIO的聊天室

  Socket.IO 是一个库,可以在客户端和服务器之间实现 低延迟, 双向 和 基于事件的 通信。

一、Socket.IO的特点

以下是 Socket.IO 在普通 WebSockets 上提供的功能:

1、HTTP 长轮询回退

如果无法建立 WebSocket 连接,连接将回退到 HTTP 长轮询。
这个特性是人们在十多年前创建项目时使用 Socket.IO 的原因(!),因为浏览器对 WebSockets 的支持仍处于起步阶段。
即使现在大多数浏览器都支持 WebSockets(超过97%),它仍然是一个很棒的功能,因为我们仍然会收到来自用户的报告,这些用户无法建立 WebSocket 连接,因为他们使用了一些错误配置的代理。

2、自动重新连接

在某些特定情况下,服务器和客户端之间的 WebSocket 连接可能会中断,而双方都不知道链接的断开状态。
这就是为什么 Socket.IO 包含一个心跳机制,它会定期检查连接的状态。
当客户端最终断开连接时,它会以指数回退延迟自动重新连接,以免使服务器不堪重负。

3、数据包缓冲

当客户端断开连接时,数据包会自动缓冲,并在重新连接时发送。

4、收到后的回调

Socket.IO 提供了一种方便的方式来发送事件和接收响应

5、广播

在服务器端,您可以向所有连接的客户端或客户端的子集发送事件

6、多路复用

命名空间允许您在单个共享连接上拆分应用程序的逻辑。例如,如果您想创建一个只有授权用户才能加入的“管理员”频道

更多信息请访问socketIO的介绍文档

二、Socket.IO发送消息常见的方式

  socket.io用on函数给调用的时间注册调用函数,用emit函数来发送时间,以此来时间客户端和服务器两端的通信,常用的使用方式如下:

1、只发送事件

发送端代码:

socket.emit('action');

表示发送了一个action命令,命令是字符串的,在另一端接收时,可以这么写:

socket.on('action',function(){
	...
});

2、发送事件和一个数据

发送端:

socket.emit('action',data);

表示发送了一个action命令,还有data数据,在另一端接收时,可以这么写:

socket.on('action',function(data){
	...
});

3、发送事件和多个数据

发送端:

socket.emit('action',arg1,arg2);

表示发送了一个action命令,还有两个数据,在另一端接收时,可以这么写:

socket.on('action',function(arg1,arg2){
	...
});

如果是多个参数,就在后面加参数就行了

4、发送事件和数据及回调函数

在emit方法中包含回调函数,例如:

socket.emit('action',data, function(arg1,arg2){
	...
} );

那么这里面有一个回调函数可以在另一端调用,另一端可以这么写:

socket.on('action',function(data,fn){ 
    ...
    fn('a','b');
    ...
 });

三、emit发送消息的范围

下面是emit不同方法发送消息的范围:

  // 只发给sender。 sending to the client
  socket.emit('hello', 'can you hear me?', 1, 2, 'abc');

  // 发给所有人,除了sender。 sending to all clients except sender
  socket.broadcast.emit('broadcast', 'hello friends!');

  // 发给game房间所有人,除了sender。 sending to all clients in 'game' room except sender
  socket.to('game').emit('nice game', "let's play a game");

  // 发给game1和/或game2所有人,除了sender。 sending to all clients in 'game1' and/or in 'game2' room, except sender
  socket.to('game1').to('game2').emit('nice game', "let's play a game (too)");

  // 发给game房间所有人,包含sender。 sending to all clients in 'game' room, including sender
  io.in('game').emit('big-announcement', 'the game will start soon');

  // 发给域名myNamespacs所有人,包含sender。 sending to all clients in namespace 'myNamespace', including sender
  io.of('myNamespace').emit('bigger-announcement', 'the tournament will start soon');

  // 发给域名myNamespace里room房间的所有人,包含sender。 sending to a specific room in a specific namespace, including sender
  io.of('myNamespace').to('room').emit('event', 'message');

  // 发给某一个人 sending to individual socketid (private message)
  io.to(`${socketId}`).emit('hey', 'I just met you');

四、聊天室实现

1、项目结构

在这里插入图片描述

2、server.js

server.js实现了一个web服务器,主要的功能有两个

  • 实现一个nodejs的服务器,让浏览器能够加载到聊天网页
  • 用socket.io实现服务端接受客户连接和发送消息的功能
    其代码如下:
'use strict'

// 配置日志
const log4j = require('log4js');
const logger = log4j.getLogger();

// 配置http服务器
const {createServer} = require('http');
const express = require('express');
const serveIndex = require('serve-index');

const app = express();
// 配置静态文件,位置不能乱
app.use(serveIndex('./public'));
app.use(express.static('./public'));

// 创建http服务器
const http_server = createServer(app);

// 配置socket io
const {Server} = require("socket.io");
// 让socketIo监听https服务器

const io = new Server(http_server);


// 配置socket发送消息逻辑
io.on('connection', (socket) => {
    logger.info('socket connection : ', socket);
    //socket.emit('joined',room,socket.id);只给当前用户发送
    //socket.to(room).emit('joined', room, socket.id);//除自己之外
    //io.in(room).emit('joined', room, socket.id)//房间内所有人
    //socket.broadcast.emit('joined', room, socket.id);//除自己,全部站点
    // 加入房间的处理逻辑
    socket.on('join', (room, userName) => {
        logger.info(`user join in. userName=${userName},room=${room}`);
        // socket加入room中
        socket.join(room);
        // 发送给当前用户用户加入成功
        socket.emit('joined', room, socket.id);
    });

    // 离开房间的处理逻辑
    socket.on('leave', (room, userName) => {
        logger.info(`user leave. userName=${userName},room=${room}`);
        socket.leave(room);
        socket.emit('leaved', room, socket.id);
    })

    // 发送消息逻辑
    socket.on('message', (room, data) => {
        // 给房间内的所有人发送消息(包括自己)
        io.in(room).emit('message', data);
        //不给自己发,只给别人发(前端需要适配自己发送的内容到消息显示框)
        //socket.to(room).emit('message', data);
    })

});

//启动服务器
http_server.listen(80);

3、index.html

index.html是聊天的网页,代码如下:

<html>
<head>
    <title>Chat room</title>
    <link rel="stylesheet" href="./css/main.css">
</head>

<body>
<table align="center">
    <tr>
        <td>
            <label>UserName:</label>
            <input type="text" id="userName">
        </td>
    </tr>
    <tr>
        <td>
            <label>Room:</label>
            <input type="text" id="room">
            <button id="connect">Connect</button>
            <button id="leave">Leave</button>
        </td>
    </tr>
    <tr>
        <td>
            <label>Content: </label><br>
            <textarea disabled style="line-height: 1.5;" id="content" rows="10" cols="100"></textarea>
        </td>
    </tr>
    <tr>
        <td>
            <label>Input: </label><br>
            <textarea disabled id="input" rows="3" cols="100"></textarea>
        </td>
    </tr>
    <tr>
        <td>
            <button disabled id="send">Send</button>
        </td>
    </tr>
</table>


<script src="/socket.io/socket.io.js"></script>
<script src="./js/client.js"></script>
</body>

</html>

4、main.css

main.css是index.html的布局格式文件,代码如下:

/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
button {
  margin: 0 20px 25px 0;
  vertical-align: top;
  width: 134px;
}

div#getUserMedia {
  padding: 0 0 8px 0;
}

div.input {
  display: inline-block;
  margin: 0 4px 0 0;
  vertical-align: top;
  width: 310px;
}

div.input > div {
  margin: 0 0 20px 0;
  vertical-align: top;
}

div.output {
  background-color: #eee;
  display: inline-block;
  font-family: 'Inconsolata', 'Courier New', monospace;
  font-size: 0.9em;
  padding: 10px 10px 10px 25px;
  position: relative;
  top: 10px;
  white-space: pre;
  width: 270px;
}

section#statistics div {
  display: inline-block;
  font-family: 'Inconsolata', 'Courier New', monospace;
  vertical-align: top;
  width: 308px;
}

section#statistics div#senderStats {
  margin: 0 20px 0 0;
}

section#constraints > div {
  margin: 0 0 20px 0;
}

section#video > div {
  display: inline-block;
  margin: 0 20px 0 0;
  vertical-align: top;
  width: calc(50% - 22px);
}

section#video > div div {
  font-size: 0.9em;
  margin: 0 0 0.5em 0;
  width: 320px;
}

h2 {
  margin: 0 0 1em 0;
}

section#constraints label {
  display: inline-block;
  width: 156px;
}

section {
  margin: 0 0 20px 0;
  padding: 0 0 15px 0;
}

section#video {
  width: calc(100% + 20px);
}

video {
  --width: 90%;
  display: inline-block;
  width: var(--width);
  height: calc(var(--width) * 0.75);
  margin: 0 0 10px 0;
}

@media screen and (max-width: 720px) {
  button {
    font-weight: 500;
    height: 56px;
    line-height: 1.3em;
    width: 90px;
  }

  div#getUserMedia {
    padding: 0 0 40px 0;
  }

  section#statistics div {
    width: calc(50% - 14px);
  }

  video {
    display: inline-block;
    width: var(--width);
    height: 96px;
  }
}

5、client.js

client.js文件是客户端的处理逻辑文件,包括发送和显示消息,连接服务器等

'use strict'

// 获取页面组建
const userNameInput = document.querySelector('input#userName');
const roomInput = document.querySelector('input#room');

const connectBtn = document.querySelector('button#connect');
const leaveBtn = document.querySelector('button#leave');

const contentArea = document.querySelector('textarea#content');
const inputArea = document.querySelector('textarea#input');

const sendBtn = document.querySelector('button#send');

var socket;
// 连接逻辑
connectBtn.onclick = () => {
    //连接
    socket = io();

    // 成功加入后的逻辑
    socket.on('joined', (room, id) => {
        console.log(`join in successful,room=${room},socketId=${id}`);
        connectBtn.disabled = true;
        leaveBtn.disabled = false;
        inputArea.disabled = false;
        sendBtn.disabled = false;
        roomInput.disabled = true;
        userNameInput.disabled = true;
    });

    //离开成功的逻辑
    socket.on('leaved', (room, id) => {
        console.log(`user leave ,room=${room},socketId=${id}`);
        connectBtn.disabled = false;
        leaveBtn.disabled = true;
        inputArea.disabled = true;
        sendBtn.disabled = true;
        roomInput.disabled = false;
        userNameInput.disabled = false;
        socket.disconnect();
    });

    // 断开连接
    socket.on('disconnect', (socket) => {
        connectBtn.disabled = false;
        leaveBtn.disabled = true;
        inputArea.disabled = true;
        sendBtn.disabled = true;
        roomInput.disabled = false;
        userNameInput.disabled = false;
    });

    // 接受到消息的逻辑
    socket.on('message', (data) => {
        //窗口总是显示最后的内容
        contentArea.scrollTop = contentArea.scrollHeight;
        contentArea.value = contentArea.value + data + '\r';
    });

    // 发送加入的信令
    socket.emit('join', roomInput.value, userNameInput.value);
}

//断开连接
leaveBtn.onclick = () => {
    socket.emit('leave', roomInput.value, userNameInput.value);
}

//发送消息的逻辑
sendBtn.onclick = () => {
    sendMessage();
}

// 回车发送消息的逻辑
inputArea.onkeypress = (event) => {
    //回车发送消息
    if (event.keyCode !== 13) {
        return;
    }
    sendMessage();
    //阻止默认行为
    event.preventDefault();
}

function sendMessage() {
    let data = userNameInput.value + ' : ' + inputArea.value;
    socket.emit('message', roomInput.value, data);
    inputArea.value = '';
}

6、启动服务器

找到项目所在的目录,安装项目需要的模块

npm install express serve-index log4js socket.io

用以下命令启动服务器

node server.js

7、功能演示

打开两个浏览器的窗口,分别输入项目地址http://localhost/index.html(如果是别的ip,将localhost换成对应的ip地址),在浏览器上面输入用户名(不同),房间room(相同),点击connect按钮就可以发送消息。
在这里插入图片描述
另一个客户端:
在这里插入图片描述


后记
  个人总结,欢迎转载、评论、批评指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/172311.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文化传承与数字技术的完美结合:十八数藏的新纪元

在这数字化的时代&#xff0c;十八数藏犹如一座连接过去与未来的桥梁&#xff0c;展现出文化传承与数字技术完美结合的新纪元。十八数藏以其独特的视角&#xff0c;将传统文化注入现代数字技术的脉络&#xff0c;呈现出一幅文化传承的全新画卷。 十八数藏的文化传承并不是简单的…

C++进阶篇5-哈希

一、unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到log_2N&#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的节点非常多时&#xff0c;查询效率也不理想。最优的查询是&#xff0…

Linux—简介安装常用命令系统中软件安装项目部署

目录 1. 前言1.1 什么是Linux1.2 为什么要学Linux1.3 学完Linux能干什么 2. Linux简介2.1 主流操作系统2.2 Linux发展历史2.3 Linux系统版本 3. Linux安装3.1 安装方式介绍3.2 安装VMware3.3 安装Linux3.4 网卡设置3.5 安装SSH连接工具3.5.1 SSH连接工具介绍3.5.2 FinalShell安…

leetcode:1773. 统计匹配检索规则的物品数量(python3解法)

难度&#xff1a;简单 给你一个数组 items &#xff0c;其中 items[i] [typei, colori, namei] &#xff0c;描述第 i 件物品的类型、颜色以及名称。 另给你一条由两个字符串 ruleKey 和 ruleValue 表示的检索规则。 如果第 i 件物品能满足下述条件之一&#xff0c;则认为该物…

Softing TCS:高效的诊断模拟解决方案

| Softing TCS——高效的仿真模拟ECU或整车解决方案 现代诊断模拟Softing TCS是当相应的测试物还没有或不再可用时的解决方案。这种情况通常出现在早期阶段的组件和车辆工程、测试仪回归测试中或在对教学设施进行功能验证时&#xff0c;因为它们需要对多种不同的测试对象进行验…

Python之pyc文件的生成与反编译

目录 1、什么是pyc文件 2、手动生成pyc文件 3、pyc文件的执行 4、pyc文件的反编译 1、什么是pyc文件 pyc文件&#xff08;PyCodeObject&#xff09;是Python编译后的结果。当python程序运行时&#xff0c;编译的结果是保存于PyCodeObject&#xff0c;程序运行结束后&#x…

linux基本指令以及热键

基本指令 ♥clear ♥whoami ♥who ♥pwd ♥ls指令&#xff08;重点&#xff09; ls -a&#xff1a; ls -l ♥mkdir ♥cd指令 ♥touch指令 ♥stat指令 ♥rmdir指令 && rm 指令 ♥man指令 ♥nano指令 ♥cp指令 ♥mv指令 ♥cat指令 &#x1f5e1;输出/输出重定向 &#x1…

速锐得解码匹配驾培驾考吉利几何E萤火虫数据应用智能评判系统

随着国内新能源车的不断发展和渗透&#xff0c;在驾培驾考领域通过新能源车进入到驾驶员培训领域的车型越来越多&#xff0c;这里边包括了特斯拉、宝马、通用、沃尔沃、岚图、江淮、蔚来、比亚迪、吉利、奇瑞、大众等多家车企的车型。 之前我们做过像奇瑞艾瑞泽、江淮IEV7、大…

大华智能物联综合管理平台readpic接口任意文件读取漏洞复现 [附POC]

文章目录 大华智能物联综合管理平台readpic接口任意文件读取漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 大华智能物联综合管理平台readpic接口任意文件读取漏洞复现 [附POC] 0x01 前言 免责…

微信小程序知识付费平台,公众号App+SAAS+讲师端,多端部署

三勾知识付费系统基于thinkphp8element-plusuniapp打造的面向开发的知识付费系统&#xff0c;方便二次开发或直接使用&#xff0c;可发布到多端&#xff0c;包括微信小程序、微信公众号、QQ小程序、支付宝小程序、字节跳动小程序、百度小程序、android端、ios端。 功能包含直播…

2022最新版-李宏毅机器学习深度学习课程-P49 GPT的野望

GPT→类似于Transformer Encoder 训练任务&#xff1a;Predict Next Token 使用MASK-attention&#xff0c;不断预测“下一个token”。 可以用GPT生成文章。 How to use GPT? 给出描述和例子 给出前半段&#xff0c;补上后半段 In-context Learning(no GD) 结果 目前看起…

竞赛 题目:基于深度学习的图像风格迁移 - [ 卷积神经网络 机器视觉 ]

文章目录 0 简介1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习卷积神经网络的花卉识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c…

初步设计报告(框架)

前言 &#xff08;简述初步设计报告编制的背景、过程及其它有关情况&#xff09;&#xff08;内容可根据项目的实际建设内容进行选择&#xff09; 编制单位资质证明

el-checkbox 对勾颜色调整

对勾默认是白色 改的时候一直在试着改color人&#xff0c;其实不对。我用的是element ui 的复选框 /* 对勾颜色调整 */ .el-checkbox__inner::after{/* 是改这里的颜色 */border: 2px solid #1F7DFD; border-left: 0;border-top: 0;}

CAD文件转奥维 转shapefile

之前写过一篇CAD转ArcGIS 其实万变不离其宗&#xff0c;都是经纬度知识的应用。 背景是当我们拿到一份带有坐标的CAD文件如何转换为矢量文件。 首先我们要明白XY坐标系的含义。 X—real X-500000 为近距离标准经线的距离。 y 为距离赤道的距离。 X 429174.3048 Y 32313…

太累了,是时候让AI数字人来帮我干活了(走,上教程)

阿酷TONY&#xff0c;原创文章&#xff0c;长沙&#xff0c;2023.11.21 关 键 词&#xff1a;AI数字人&#xff0c;生成式AI&#xff0c;智能数字分身适用场景&#xff1a;培训数字人&#xff0c;演讲授课数字人&#xff0c;直播带货数字人特别说明&#xff1a;教程用的是国内…

后端-锁专题:synchronized(java对象结构、锁的类型、锁升级流程...)

文章目录 对象的结构以及大小内存换算java的常见数据类型以及所占字节数分析对象总共占多少字节&#xff0c;各项占多少字节对象头结构 锁类型锁升级流程 对象的结构以及大小内存换算 java的常见数据类型以及所占字节数 String&#xff1a;8字节 64位 int&#xff1a;4字节 …

竞赛选题 车位识别车道线检测 - python opencv

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) …

阵列 MEMS-IMU的解算系统

使用飞速发展的硅半导体工艺制成的微机械电子系统&#xff08;Micro Electro Mechanical System&#xff0c;MEMS&#xff09;具有体积小、成本低、重量轻、低功耗等诸多优势。MEMS-IMU&#xff08;Inertial Measurement Unit, IMU&#xff09;构成的捷联惯导系统可以应用到无人…

抖音预约服务小程序开发:前端与后端技术的完美融合

开发抖音预约服务小程序成为了一种有趣而又实用的尝试。本篇文章&#xff0c;小编会与大家共同探讨抖音预约服务小程序开发的前端与后端技术融合的关键要点。 一、前端技术选择与设计 1.小程序框架 开发抖音预约服务小程序的前端&#xff0c;首先需要选择一个适用的小程序框…