iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >node.js中如何使用socket.io实现一个实时通讯应用
  • 781
分享到

node.js中如何使用socket.io实现一个实时通讯应用

2023-06-17 07:06:46 781人浏览 安东尼
摘要

今天小编给大家分享一下node.js中如何使用Socket.io实现一个实时通讯应用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一

今天小编给大家分享一下node.js中如何使用Socket.io实现一个实时通讯应用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

WebSocket概念

不同于Http半双工协议,websocket是基于tcp 连接的全双工协议,支持客户端服务端双向通信。

WEBSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket api 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

node.js中如何使用socket.io实现一个实时通讯应用

实现

原生实现

WebSocket对象一共支持四个消息 onopen, onmessage, onclose和onerror。

建立连接

通过javascript可以快速的建立一个WebSocket连接:

var Socket = new WebSocket(url, [protocol] );

以上代码中的第一个参数url, 指定连接的URL。第二个参数 protocol是可选的,指定了可接受的子协议。

同http协议使用http://开头一样,WebSocket协议的URL使用ws://开头,另外安全的WebSocket协议使用wss://开头。

当Browser和WebSocketServer连接成功后,会触发onopen消息。

Socket.onopen = function(evt) {};

如果连接失败,发送、接收数据失败或者处理数据出现错误,browser会触发onerror消息。

Socket.onerror = function(evt) { };

当Browser接收到WebSocketServer端发送的关闭连接请求时,就会触发onclose消息。

Socket.onclose = function(evt) { };

收发消息

当Browser接收到WebSocketServer发送过来的数据时,就会触发onmessage消息,参数evt中包含server传输过来的数据。

Socket.onmessage = function(evt) { };

send用于向服务端发送消息。

Socket.send();

socket

WebSocket是跟随HTML5一同提出的,所以在兼容性上存在问题,这时一个非常好用的库就登场了——Socket.io。

socket.io封装了websocket,同时包含了其它的连接方式,你在任何浏览器里都可以使用socket.io来建立异步的连接。socket.io包含了服务端和客户端的库,如果在浏览器中使用了socket.io的js,服务端也必须同样适用。

socket.io是基于 Websocket 的Client-Server 实时通信库。

socket.io底层是基于engine.io这个库。engine.io为 socket.io 提供跨浏览器/跨设备的双向通信的底层库。engine.io使用了 Websocket 和 XHR 方式封装了一套 socket 协议。在低版本的浏览器中,不支持Websocket,为了兼容使用长轮询(polling)替代。

API文档

Socket.io允许你触发或响应自定义的事件,除了connect,message,disconnect这些事件的名字不能使用之外,你可以触发任何自定义的事件名称。

建立连接

  const socket = io("ws://0.0.0.0:port"); // port为自己定义的端口号  let io = require("socket.io")(http);  io.on("connection", function(socket) {})

消息收发

一、发送数据

socket.emit(自定义发送的字段, data);

二、接收数据

 socket.on(自定义发送的字段, function(data) {    console.log(data);  })

断开连接

一、全部断开连接

  let io = require("socket.io")(http);  io.close();

二、某个客户端断开与服务端的链接

  // 客户端  socket.emit("close", {});
 // 服务端  socket.on("close", data => {    socket.disconnect(true);  });

room和namespace

有时候websocket有如下的使用场景:1.服务端发送的消息有分类,不同的客户端需要接收的分类不同;2.服务端并不需要对所有的客户端都发送消息,只需要针对某个特定群体发送消息;

针对这种使用场景,socket中非常实用的namespace和room就上场了。

先来一张图看看namespace与room之间的关系:

node.js中如何使用socket.io实现一个实时通讯应用

namespace

服务端

  io.of("/post").on("connection", function(socket) {    socket.emit("new message", { mess: `这是post的命名空间` });  });    io.of("/get").on("connection", function(socket) {    socket.emit("new message", { mess: `这是get的命名空间` });  });

客户端

  // index.js  const socket = io("ws://0.0.0.0:****/post");  socket.on("new message", function(data) {    console.log('index',data);  }    //message.js  const socket = io("ws://0.0.0.0:****/get");  socket.on("new message", function(data) {    console.log('message',data);  }

room

客户端

 //可用于客户端进入房间;  socket.join('room one');  //用于离开房间;  socket.leave('room one');

服务端

  io.sockets.on('connection',function(socket){    //提交者会被排除在外(即不会收到消息)    socket.broadcast.to('room one').emit('new messages', data);    // 向所有用户发送消息    io.sockets.to(data).emit("recive message", "hello,房间中的用户");     }

用socket.io实现一个实时接收信息的例子

终于来到应用的阶段啦,服务端用node.js模拟了服务端接口。以下的例子都在本地服务器中实现。

服务端

先来看看服务端,先来开启一个服务,安装expresssocket.io

安装依赖

npm install --Dev expressnpm install --Dev socket.io

构建node服务器

 let app = require("express")();  let http = require("http").createServer(handler);  let io = require("socket.io")(http);  let fs = require("fs");    http.listen(port); //port:输入需要的端口号    function handler(req, res) {   fs.readFile(__dirname + "/index.html", function(err, data) {    if (err) {     res.writeHead(500);     return res.end("Error loading index.html");    }      res.writeHead(200);    res.end(data);   });  }    io.on("connection", function(socket) {    console.log('连接成功');    //连接成功之后发送消息    socket.emit("new message", { mess: `初始消息` });      });

客户端

核心代码——index.html(向服务端发送数据)

 <div>发送信息</div>  <input placeholder="请输入要发送的信息" />  <button onclick="postMessage()">发送</button>
 // 接收到服务端传来的name匹配的消息  socket.on("new message", function(data) {   console.log(data);  });    function postMessage() {   socket.emit("recive message", {    message: content,    time: new Date()   });   messList.push({    message: content,    time: new Date()   });  }

核心代码——message.html(从服务端接收数据)

socket.on("new message", function(data) {   console.log(data);  });

效果

实时通讯效果

node.js中如何使用socket.io实现一个实时通讯应用

客户端全部断开连接

node.js中如何使用socket.io实现一个实时通讯应用

某客户端断开连接

node.js中如何使用socket.io实现一个实时通讯应用

namespace应用

node.js中如何使用socket.io实现一个实时通讯应用

加入房间

node.js中如何使用socket.io实现一个实时通讯应用

离开房间

node.js中如何使用socket.io实现一个实时通讯应用

框架中的应用

npm install socket.io-client
const socket = require('socket.io-client')('http://localhost:port');  componentDidMount() {    socket.on('login', (data) => {      console.log(data)    });    socket.on('add user', (data) => {      console.log(data)    });    socket.on('new message', (data) => {      console.log(data)    });  }

分析webSocket协议

Headers

node.js中如何使用socket.io实现一个实时通讯应用

请求包

 Accept-Encoding: gzip, deflate  Accept-Language: zh-CN,zh;q=0.9,en;q=0.8  Cache-Control: no-cache  Connection: Upgrade  Cookie: MEIQIA_VISIT_ID=1IcBRlE1mZhdVi1dEFNtGNAfjyG; token=0b81ffd758ea4a33e7724d9c67efbb26; io=ouI5Vqe7_WnIHlKnAAAG  Host: 0.0.0.0:2699  Origin: http://127.0.0.1:5500  Pragma: no-cache  Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits  Sec-WebSocket-Key: PJS0iPLxrL0ueNPoAFUSiA==  Sec-WebSocket-Version: 13  Upgrade: websocket  User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

请求包说明:

  • 必须是有效的http request 格式;

  • HTTP request method 必须是GET,协议应不小于1.1 如: Get / HTTP/1.1;

  • 必须包括Upgrade头域,并且其值为“websocket”,用于告诉服务器此连接需要升级到websocket;

  • 必须包括”Connection” 头域,并且其值为“Upgrade”;

  • 必须包括”Sec-WebSocket-Key”头域,其值采用base64编码的随机16字节长的字符序列;

  • 如果请求来自浏览器客户端,还必须包括Origin头域 。 该头域用于防止未授权的跨域脚本攻击,服务器可以从Origin决定是否接受该WebSocket连接;

  • 必须包括“Sec-webSocket-Version”头域,是当前使用协议的版本号,当前值必须是13;

  • 可能包括“Sec-WebSocket-Protocol”,表示client(应用程序)支持的协议列表,server选择一个或者没有可接受的协议响应之;

  • 可能包括“Sec-WebSocket-Extensions”, 协议扩展, 某类协议可能支持多个扩展,通过它可以实现协议增强;

  • 可能包括任意其他域,如cookie.

应答包

应答包说明:

 Connection: Upgrade  Sec-WebSocket-Accept: I4jyFwm0r1J8lrnD3yN+EvxTABQ=  Sec-WebSocket-Extensions: permessage-deflate  Upgrade: websocket
  • 必须包括Upgrade头域,并且其值为“websocket”;

  • 必须包括Connection头域,并且其值为“Upgrade”;

  • 必须包括Sec-WebSocket-Accept头域,其值是将请求包“Sec-WebSocket-Key”的值,与”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″这个字符串进行拼接,然后对拼接后的字符串进行sha-1运算,再进行base64编码,就是“Sec-WebSocket-Accept”的值;

  • 应答包中冒号后面有一个空格;

  • 最后需要两个空行作为应答包结束。

请求数据

 EIO: 3  transport: websocket  sid: 8Uehk2UumXoHVJRzAAAA
  • EIO:3 表示使用的是engine.io协议版本3

  • transport 表示传输采用的类型

  • sid: session id (String)

Frames

WebSocket协议使用帧(Frame)收发数据,在控制台->Frames中可以查看发送的帧数据。

其中帧数据前的数字代表什么意思呢?

这是 Engine.io协议,其中的数字是数据包编码:

<Packet type id> [<data>]

0 open——在打开新传输时从服务器发送(重新检查)

1 close——请求关闭此传输,但不关闭连接本身。

2 ping——由客户端发送。服务器应该用包含相同数据的乓包应答

客户端发送:2probe探测帧

3 pong——由服务器发送以响应ping数据包。

服务器发送:3probe,响应客户端

4 message——实际消息,客户端和服务器应该使用数据调用它们的回调。

5 upgrade——在engine.io切换传输之前,它测试,如果服务器和客户端可以通过这个传输进行通信。如果此测试成功,客户端发送升级数据包,请求服务器刷新其在旧传输上的缓存并切换到新传输。

6 noop——noop数据包。主要用于在接收到传入WebSocket连接时强制轮询周期。

实例

node.js中如何使用socket.io实现一个实时通讯应用

node.js中如何使用socket.io实现一个实时通讯应用

以上的截图是上述例子中数据传输的实例,分析一下大概过程就是:

  • connect握手成功

  • 客户端会发送2 probe探测帧

  • 服务端发送响应帧3probe

  • 客户端会发送内容为5的Upgrade帧

  • 服务端回应内容为6的noop帧

  • 探测帧检查通过后,客户端停止轮询请求,将传输通道转到websocket连接,转到websocket后,接下来就开始定期(默认是25秒)的 ping/pong

  • 客户端、服务端收发数据,4表示的是engine.io的message消息,后面跟随收发的消息内容

为了知道Client和Server链接是否正常,项目中使用的ClientSocket和ServerSocket都有一个心跳的线程,这个线程主要是为了检测Client和Server是否正常链接,Client和Server是否正常链接主要是用ping pong流程来保证的。

该心跳定期发送的间隔是socket.io默认设定的25m,在上图中也可观察发现。该间隔可通过配置修改。

node.js中如何使用socket.io实现一个实时通讯应用

以上就是“node.js中如何使用socket.io实现一个实时通讯应用”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

--结束END--

本文标题: node.js中如何使用socket.io实现一个实时通讯应用

本文链接: https://www.lsjlt.com/news/287689.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c++中if elseif使用规则
    c++ 中 if-else if 语句的使用规则为:语法:if (条件1) { // 执行代码块 1} else if (条件 2) { // 执行代码块 2}// ...else ...
    99+
    2024-05-14
    c++
  • c++中的继承怎么写
    继承是一种允许类从现有类派生并访问其成员的强大机制。在 c++ 中,继承类型包括:单继承:一个子类从一个基类继承。多继承:一个子类从多个基类继承。层次继承:多个子类从同一个基类继承。多层...
    99+
    2024-05-14
    c++
  • c++中如何使用类和对象掌握目标
    在 c++ 中创建类和对象:使用 class 关键字定义类,包含数据成员和方法。使用对象名称和类名称创建对象。访问权限包括:公有、受保护和私有。数据成员是类的变量,每个对象拥有自己的副本...
    99+
    2024-05-14
    c++
  • c++中优先级是什么意思
    c++ 中的优先级规则:优先级高的操作符先执行,相同优先级的从左到右执行,括号可改变执行顺序。操作符优先级表包含从最高到最低的优先级列表,其中赋值运算符具有最低优先级。通过了解优先级,可...
    99+
    2024-05-14
    c++
  • c++中a+是什么意思
    c++ 中的 a+ 运算符表示自增运算符,用于将变量递增 1 并将结果存储在同一变量中。语法为 a++,用法包括循环和计数器。它可与后置递增运算符 ++a 交换使用,后者在表达式求值后递...
    99+
    2024-05-14
    c++
  • c++中a.b什么意思
    c++kquote>“a.b”表示对象“a”的成员“b”,用于访问对象成员,可用“对象名.成员名”的语法。它还可以用于访问嵌套成员,如“对象名.嵌套成员名.成员名”的语法。 c++...
    99+
    2024-05-14
    c++
  • C++ 并发编程库的优缺点
    c++++ 提供了多种并发编程库,满足不同场景下的需求。线程库 (std::thread) 易于使用但开销大;异步库 (std::async) 可异步执行任务,但 api 复杂;协程库 ...
    99+
    2024-05-14
    c++ 并发编程
  • 如何在 Golang 中备份数据库?
    在 golang 中备份数据库对于保护数据至关重要。可以使用标准库中的 database/sql 包,或第三方包如 github.com/go-sql-driver/mysql。具体步骤...
    99+
    2024-05-14
    golang 数据库备份 mysql git 标准库
  • 如何在 Golang 中优雅地处理错误?
    在 go 中,优雅处理错误包括:使用 error 类型;使用 errors 包函数和类型;自定义错误类型;遵循错误处理模式,包括关闭资源、检查错误、打印错误信息和处理或返回错误。 在 ...
    99+
    2024-05-14
    golang 错误处理
  • 如何构建 Golang RESTful API,并使用中间件进行身份验证?
    本文介绍了如何构建 golang restful api。首先,通过导入必要的库、定义数据模型和创建路由来构建 restful api。其次,使用 go-chi/chigot 和 go-...
    99+
    2024-05-14
    golang git
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作