实时通信协议

本文旨在简要解释如何在Web上实现客户端/服务器和客户端/客户端之间的实时通信,以及它们的内部工作原理和最常见的用例。

TCP vs UDP

TCP和UDP都位于OSI模型的传输层,负责在网络上传输数据包。它们之间的主要区别在于,TCP在传输数据之前会打开一个专用连接,并确保所有数据包都到达目的地,而UDP则不会。这使得TCP连接速度较慢,但同时更可靠,因为它确保数据的到达,而UDP可能更快,但在传输过程中可能会丢失一些数据包。

这个概念在选择实时通信技术时需要牢记,因为它们可能使用TCP或UDP作为传输层协议,具有各自的优势和劣势。例如,如果您正在开发一个视频会议平台,用户更希望彼此之间的交互更快,而丢失一些数据包是可以接受的。

WebSockets

WebSocket是一种HTTP升级技术,它提供了基于TCP的持久全双工、双向连接。它被设计为客户端/服务器连接,允许它们随时相互发送数据。

1*1CUCOOXEIhcDzBWMDDQb6g.png

握手

为了建立WebSocket连接,客户端必须向服务器发送一个HTTP 握手 请求以切换协议:

GET /chat HTTP/1.1Host: my-awesome.server.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: s3TTHMbDL1HtLzh1GKh12t==Sec-WebSocket-Protocol: chatSec-WebSocket-Version: 13Origin: http://my-awesome.server.com

如果满足要求,服务器将以HTTP Upgrade 101 Switching Protocols 响应来回应,如果不满足要求,则返回HTTP错误:

HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat

请注意,客户端请求包含一个带有Base64编码的随机字节值的 Sec-WebSocket-Key,而服务器则回复一个带有请求密钥的哈希值的 Sec-WebSocket-Accept 头。这是为了防止缓存代理重新发送先前的WebSocket连接。

实现

一旦握手被接受,客户端已切换协议,客户端可以向服务器发送数据,服务器也可以向客户端发送数据。

在客户端中,使用浏览器的本机JavaScript引擎,由服务器发送的传入数据将由事件函数处理,一旦数据到达,这些事件函数将被触发。

在服务器端,在大多数情况下,这也是处理客户端发送的数据的方式,但也可以通过永不结束的循环来处理数据。

// HTTP握手const socket = new WebSocket(\\\'ws://my-awesome.server.com\\\');
socket.onopen = (event) => { // 连接建立时触发 socket.send(\\\'客户端发送到服务器的数据\\\');});
socket.onmessage = (event) => { // 服务器发送数据时触发 console.log(event.data);});
socket.onclose = (event) => { // WebSocket连接关闭时触发 console.log(\\\'连接关闭\\\')});

预期使用案例

当您需要低延迟的实时连接时,WebSocket是一种非常强大的协议,基于Web的游戏、聊天应用程序是可以使用此技术的很好的示例,因为在客户端之间进行通信非常简单:客户端A可以通过服务器向客户端B发送消息。

实时通信协议
1*DDl3U145ns-peMbMagQU8A.png

广播可以通过记录每个连接的客户端轻松完成,假设我们需要更新游戏的排行榜,服务器可以将相同的消息发送给每个连接的客户端。

实时通信协议
1*RJALC3NM0ZvRADUFFfFAHQ.png

SocketIO

SocketIO[1] 是一个事件驱动的JavaScript库,可在服务器和客户端中使用,以更高效地处理WebSocket。它包括自动重新连接和故障回退机制,如果握手失败,将提供长轮询连接作为实时连接。此外,它提供了命名空间和房间广播事件,您可以仅将消息发送到特定的通道。

WebRTC

WebRTC是一种基于UDP的技术,提供点对点通信。该协议的主要优点是它在对等方之间具有非常低的延迟。信息是从客户端传输到客户端,无需中央服务器,并且使用UDP协议作为传输层使连接速度非常快。它通常用于涉及实时媒体通信的应用程序,其中丢失一些数据包并不是大问题。

默认情况下,WebRTC提供端到端加密,使连接在通过互联网传输时保持安全。

信令

此过程用于对等方之间交换其连接。为了实现这一点,需要一个具有已连接对等方信息的服务器来建立此连接。

要实现这一点,一个对等方必须发送一个带有其会话描述协议(SDP)

的提议,其中包括有关客户端的关键信息,例如要接收的内容(例如视频、音频、两者兼有)、浏览器支持的选项、编解码器等。您要连接的对等方将接收此提议请求并存储此会话描述,并创建一个答案。

当另一个对等方接收到响应时,它将存储到达的会话描述作为远程描述。在完成此操作后,两个对等方可以使用已建立的流相互连接。两个对等方将交换其ICE候选项,其中包含两者都需要通过互联网连接所需的信息(IP地址、端口等)。一旦完成,连接应该正常运行,对等方可以交换媒体。

STUN/TURN服务器

这个方案的主要困难在于连接在防火墙后工作,因此连接将被拒绝。为了克服这个问题,STUN服务器将帮助我们获取对等方的IP或对等方的IP。因此,在ICE候选项中,将设置STUN的IP和端口,以便对等方将与服务器通信,然后代理到客户端。

在大多数情况下,此配置将足够,但在某些情况下,对等方的安全性较高,STUN服务器将无法解开其他对等方的地址。这就是TURN服务器的出现,它是连接的对等方之间的中介对等方。对等方将媒体发送到此服务器,它将能够将其发送回其他对等方。

实时通信协议
1*1sogm-7H_BSRWhlRPdxyVA.png

应用

如上所述,此技术在尝试向一个或多个对等方传输媒体(如音频、视频或两者)时产生差异。这就是为什么应用程序如Google Meet、Discord、Twitch使用它作为其实时通信机制的原因,使连接在每个连接的对等方之间保持安全且快速。使用WebRTC进行广播非常容易实现,延迟非常低,而使用其他技术,如WebSockets,连接将存在较大的延迟问题,因为所有传输的媒体都会通过中央服务器发送,然后通过TCP将数据包发送回其他客户端,使过程更加安全但更慢。

文件共享是WebRTC的强项,应用程序如WebTorrent使用它在浏览器中传输点对点文件,使用BitTorrent协议。

尽管最初是为Web浏览器开发的,但使用此技术设计了许多非浏览器设备的应用程序,包括移动平台和物联网设备。

可扩展消息和出席协议(Jabber)

这是一种基于TCP的分散式协议,允许在网络上传输XML元素以实现近实时的消息和出席信息交换。

它基于客户端-服务器架构,其中一个客户端将其信息,如出席或消息,通过服务器发送给另一个客户端。如果接收方未连接到与发送方相同的服务器,则服务器将与其他XMPP服务器通信,直到找到客户端。这就是为什么这种架构是分散式的,不是每个客户端都连接到同一个中央服务器,客户端和服务器都是相互连接的。

1*qY34YQaFqusEchQIutoFGQ.png

XML流从一个客户端发送到另一个客户端,使用JID(Jabber标识),每个客户端都有一个具有以下结构的唯一标识符:

1*gFKdZ9U1XWcw6h2FQP2Acw.png

?本地部分:与电子邮件中“@”之前的部分完全相同,通常在此处使用客户端的名称。?域部分:它是指连接此客户端的服务器。?资源部分:顾名思义,用于指定要用于将消息发送到服务器的资源。例如,同一服务器可以处理来自移动应用程序、Web、桌面应用程序等的消息。

XMPP Stanza

XMPP stanza是从客户端之间发送的XML元素,充当了从客户端之间发送的结构化信息的基本单位。有三种主要的stanza:

?消息:?客户端到客户端?发送并忘记?无需确认?对于不需要响应的任何内容(聊天、警报、日志记录等)都很有用。

Hey, how you doin\\\'? pNltztLMBQhqakHwcFd

?信息查询:?一对一?确认?至少一次的可选交付

<iq id=\\\"30\\\" type=\\\"result\\\"   from=\\\"user-two@server.org/mobile\\\"   to=\\\"user-one@server.org/desktop\\\" />

?出席:?定向(一对一)或广播(一对多)?在网络上宣布实体的可用性

Studying away

轮询和长轮询

在创建这些协议和技术之前,开发人员创建了几种机制和策略,以实现类似实时通信的结果。在仍在使用的最著名的机制中,我想强调这两种:轮询:这种机制背后的想法是每隔x秒向服务器发送一个请求,以检查是否有新数据到达。

// 每一秒调用一次fetch以获取新消息setInterval(1000, () => {  fetch(\\\'http://my-awesome.server.com/new-messages\\\')    .then(response => response.json())    .then(data => updateInterface(data));})

长轮询:为了克服前述问题,客户端将发送请求以检查新数据。服务器将保持请求保持打开,直到新数据可用。一旦可用,服务器会响应并发送新信息。客户端收到新信息后,立即发送另一个请求,然后重复操作。

// 此函数将持续从服务器轮询数据// 它可能等待响应1毫秒,也可能等待1小时async function getNewData() {  const data = await fetch(\\\'http://my-awesome.server.com/new-messages\\\');  updateInterface(data.json());  getNewData();}
getNewData();

这两种策略实现了与RTC协议非常相似的结果,但性能问题较大,可能会通过阻塞事件循环[2]来导致屏幕冻结。

引用链接

[1] SocketIO: https://socket.io/docs/v4/
[2] 事件循环: https://felixgerschau.com/javascript-event-loop-call-stack/


原创文章,作者:小技术君,如若转载,请注明出处:https://www.sudun.com/ask/33888.html

(0)
小技术君's avatar小技术君
上一篇 2024年4月16日 上午11:45
下一篇 2024年4月16日 上午11:47

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注