websocket与socketio

前言

在做后台项目的时候,发现页面过一会弹出报错

WebSocket connection to 'ws://localhost:3000/ws' failed: 
WebSocketClient	@	WebSocketClient.js:16
initSocket	@	socket.js:21
(anonymous)	@	socket.js:45

image
正好面试会考,温习一下吧

1. 网络模型

image
以OSI7层协议划分:

1.1 应用层

模型中最靠近用户的一层,是为计算机用户提供应用接口,也为用户直接提供各种网络服务

  • HTTP

经典面试--说一下HTTP2的区别吧:

  • 二进制协议:HTTP/2 是一个二进制协议。在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础。
  • 多路复用: HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了"队头堵塞"的问题。
  • 数据流: HTTP/2 使用了数据流的概念,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流 ID ,用来区分它属于哪个数据流。
  • 头信息压缩: HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。
  • 服务器推送: HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送提前给客户端推送必要的资源,这样就可以相对减少一些延迟时间。这里需要注意的是 http2 下服务器主动推送的是静态资源,和 WebSocket 以及使用 SSE 等方式向客户端发送即时数据的推送是不同的。

"队头堵塞":队头阻塞是由 HTTP 基本的“请求 - 应答”模型所导致的。HTTP 规定报文必须是“一发一收”,这就形成了一个先进先出的“串行”队列。队列里的请求是没有优先级的,只有入队的先后顺序,排在最前面的请求会被最优先处理。如果队首的请求因为处理的太慢耽误了时间,那么队列里后面的所有请求也不得不跟着一起等待,结果就是其他的请求承担了不应有的时间成本,造成了队头堵塞的现象。

  • HTTPS

经典面试--HTTP和HTTPS协议的区别

  • HTTPS协议需要CA证书,费用较高;而HTTP协议不需要;

  • HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议;

  • 使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443;

  • HTTP协议连接很简单,是无状态的;HTTPS协议是有SSL和HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP更加安全。

  • HTTPS使用了非对称加密和对称加密:HTTPS是在HTTP的基础上增加了SSL层,服务器和客户端传输数据前先采用非对称加密算法生产一个秘钥,再用这个秘钥使用对称加密算法加密要传输的数据,这样做即保证了秘钥的安全,有提高了数据加密效率。

  • FTP 文件服务器

  • SMTP 邮件服务器

1.2 表示层

提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别

1.3 会话层

负责建立、管理和终止表示层实体之间的通信会话

1.4 传输层

建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路

  • TCP
  • UDP

1.5 网络层

通过IP寻址来建立两个节点之间的连接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。就是通常说的IP层

1.6 数据链路层

将比特组合成字节,再将字节组合成帧,使用链路层地址 (以太网使用MAC地址)来访问介质,并进行差错检测。
网络层与数据链路层的对比,通过上面的描述,我们或许可以这样理解,网络层是规划了数据包的传输路线,而数据链路层就是传输路线。不过,在数据链路层上还增加了差错控制的功能。

1.7 物理层

实际最终信号的传输是通过物理层实现的。通过物理介质传输比特流。规定了电平、速度和电缆针脚。常用设备有(各种物理设备)集线器、中继器、调制解调器、网线、双绞线、同轴电缆。这些都是物理层的传输介质。

2. WebSocket

WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接, 并进行双向数据传输。

解决问题

解决了半双工通信的弊端。它最大的特点是:服务器可以向客户端主动推动消息,客户端也可以主动向服务器推送消息。

原理

客户端向 WebSocket 服务器通知(notify)一个带有所有接收者ID(recipients IDs)的事件(event),服务器接收后立即通知所有活跃的(active)客户端,只有ID在接收者ID序列中的客户端才会处理这个事件。

3. socketIO

3.1 question

最开始我了解的socketIO是这样的:

Socket.IO 是一个封装了 Websocket、基于 Node 的 JavaScript 框架,包含 client 的 JavaScript 和 server 的 Node。其屏蔽了所有底层细节,让顶层调用非常简单。
另外,Socket.IO 还有一个非常重要的好处。其不仅支持 WebSocket,还支持许多种轮询机制以及其他实时通信方式,并封装了通用的接口。这些方式包含 Adobe Flash Socket、Ajax 长轮询、Ajax multipart streaming 、持久 Iframe、JSONP 轮询等。换句话说,当 Socket.IO 检测到当前环境不支持 WebSocket 时,能够自动地选择最佳的方式来实现网络的实时通信。--WebSocket 与 Socket.IO

或者是这样的:

Socket.IO 是一个库, 说到库其实我们都不陌生, 库是对已有的功能进行封装, 没错, 它是构建在 WebSocket 协议之上, 并提供额外的保证, 既然它是构建在 websocekt 之上, 说明它同样具有客户机与服务器之间延迟通信的功能. -- 《 Socket.IO》 解决 WebSocket 通信!

直到我看见官方说:

Socket.IO is not a WebSocket server. Please see ws instead. --https://github.com/socketio/socket.io/issues/3022

就有带你存疑了,目前没有时间去实践,先去看看官方文档

3.2 运作原理(How does that work?)

The client will try to establish a WebSocket connection if possible, and will fall back on HTTP long polling if not.
WebSocket is a communication protocol which provides a full-duplex and low-latency channel between the server and the browser. More information can be found here.
So, in the best-case scenario, provided that:

  • the browser supports WebSocket (97% of all browsers in 2020)
  • there is no element (proxy, firewall, …) preventing WebSocket connections between the client and the server

客户端首先将尝试建立 WebSocket 连接,如果没有,将回退到 HTTP 长轮询。可以将 Socket.IO 客户端视为WebSocket API的"轻微"包装器。

// 错误写法:https://github.com/socketio/socket.io/issues/3022
const socket = new WebSocket('ws://localhost:3000');

socket.onopen(() => {
  socket.send('Hello!');
});

socket.onmessage(data => {
  console.log(data);
});

// 正确写法
const socket = io('ws://localhost:3000');

socket.on('connect', () => {
  // either with send()
  socket.send('Hello!');

  // or with emit() and custom event names
  socket.emit('salutations', 'Hello!', { 'mr': 'john' }, Uint8Array.from([1, 2, 3, 4]));
});

// handle the event sent with socket.send()
socket.on('message', data => {
  console.log(data);
});

// handle the event sent with socket.emit()
socket.on('greetings', (elem1, elem2, elem3) => {
  console.log(elem1, elem2, elem3);
});

3.3 socketIO是什么

Socket.IO 是一个库,可在浏览器和服务器之间实现实时、双向和基于事件的通信。
他封装了websocket来实现通信功能,并在websocket不可用时寻找最佳替代(例如http长轮询HTTP long polling)

3.4 socketIO不是什么

Socket.IO 不是 WebSocket 实现。尽管 Socket.IO 确实尽可能使用 WebSocket 作为传输,但它会向每个数据包添加额外的元数据。这就是为什么 WebSocket 客户端将无法成功连接到 Socket.IO 服务器,而 Socket.IO 客户端也无法连接到普通的 WebSocket 服务器的原因。

// WARNING: the client will NOT be able to connect!
const socket = io('ws://echo.websocket.org');

这对我们解决问题有帮助吗?反正问题没解决,知识学到了。先这样吧

posted @ 2022-03-15 21:48  沧浪浊兮  阅读(2114)  评论(1编辑  收藏  举报