传输协议
传输协议支持将加密容器及其外部头部(以下简称“有效载荷”)从客户端传输到服务器,反之亦然。定义了多种传输协议:
连接到 WebSocket 和 HTTP 端点的 URI 格式如下:
TCP
TCP 传输的实现方式很简单,只需将所选MTProto 传输生成的有效负载通过 80、443、5222 或其他端口(help.getConfig可能会返回不同的端口号)上的普通 TCP 套接字发送即可。
请注意,如果设置了this_port_only dcOption标志,客户端必须仅使用指定的端口,而不能尝试任何其他端口。
另请注意,如果设置了force_try_ipv6 config标志,则客户端对于所有 MTProto 传输都必须优先使用 IPv6 而不是 IPv4,即使 IPv4 连接可用。
TCP 传输协议中不存在隐式确认机制:所有消息都必须显式确认。通常情况下,如果下一个查询或响应发送得很快,确认信息会放在一个容器中,与该查询或响应一起发送。例如,对于包含 RPC 查询的客户端消息,几乎总是如此:确认信息通常会随 RPC 响应一起到达。
WebSocket
WebSocket 传输的实现与 TCP 的实现几乎相同:使用指定的URI 格式,通过端口 80 与选定的 MTProto 服务器建立WebSocket连接。
注意:握手有效载荷中必须包含Sec-WebSocket-Protocol: binary头部信息。
有效载荷的帧结构仍然由所选的MTProto 传输协议管理,而不是由 WebSocket 消息管理:MTProto 有效载荷的长度由MTProto 传输协议定义,而不是由单个 WebSocket 消息的长度定义。这意味着,所有通过 WebSocket 消息接收和发送的数据都将被视为单个双工字节流,就像 TCP 一样。
使用 WebSocket 传输时,必须进行传输混淆。传输错误以与 TCP相同的方式传输。无论实际退出状态如何,WebSocket 的关闭代码始终为1000`false`(正常关闭)。在任何情况下,描述字符串都将是一个十进制编码的真实错误代码(可能会用空格进行前后填充以保持长度恒定),可以安全地忽略它。
示例实现:MadelineProto。
通过 HTTPS 的 WebSocket
要通过 HTTPS 建立 WebSocket 连接,只需使用TLS URI 格式即可。其余步骤与普通 WebSocket 连接相同。
注意:握手有效载荷中必须包含Sec-WebSocket-Protocol: binary头部信息。
HTTP
注意:在实现浏览器客户端时,建议使用 WebSocket 传输而不是 HTTP,因为它具有类似于 TCP 的全双工流逻辑;这消除了HTTP 长轮询的需要,并避免了在转发 RPC 回复时可能出现的延迟。
通过运行在传统 TCP 端口 80 上的 HTTP/1.1(带 keepalive)实现。 也可以使用 HTTPS。
消息帧并非由MTProto 传输协议管理,而是由 HTTP 协议本身处理。传输错误也不会以通常的方式传输,而是直接作为普通的 HTTP 状态码返回。
HTTP 连接与最近收到的用户查询中指定的会话(或者更准确地说,是会话 + 密钥标识符)相关联;通常情况下,所有查询都使用同一个会话,但恶意 HTTP 代理可能会破坏这一点。服务器只有在消息属于同一会话且轮到服务器响应时(即服务器已收到来自客户端的 HTTP 请求但尚未发送响应)才能将消息返回到 HTTP 连接中。
整体流程如下:客户端与服务器建立一个或多个保持活动的 HTTP 或 HTTPS 连接。如果需要发送一条或多条消息,则将这些消息打包成有效负载,然后向服务器的 URL/API 发送 POST 请求,将有效负载作为数据传输到该 URL/API。此外,`<header>` Content-Length、` Keepalive<header>` 和Host`<header>` 都是有效的 HTTP 标头。
服务器收到查询后,可能会稍等片刻(如果查询需要在短超时时间内得到响应),或者立即返回一个虚拟响应(仅确认收到容器)。无论哪种情况,响应都可以包含任意数量的消息。服务器还可以同时发送会话中可能保存的其他消息。
此外,还有一种特殊的长轮询 RPC 查询(仅适用于 HTTP 连接),它会发送最大超时时间T。如果服务器有消息要发送给该会话,则会立即返回;否则,将进入等待状态,直到服务器有消息要发送给客户端或T秒已过。如果在T秒内没有发生任何事件,则会返回一个虚拟响应(特殊消息)。
如果服务器需要向客户端发送消息,它会检查是否存在属于所需会话且处于“正在响应 HTTP 请求”(包括长轮询)状态的 HTTP 连接。如果存在,则消息会被添加到该连接的响应容器中并发送给用户。通常情况下,会预留一些额外的等待时间(50 毫秒),以防服务器很快会收到更多要发送给该会话的消息。
如果没有合适的 HTTP 连接,消息将被放入当前会话的发送队列中。但是,在客户端明确确认接收之前,消息始终会留在队列中。对于所有协议,客户端必须在合理的时间内返回明确的确认信息(该信息可以添加到容器中,以便用于下一个请求)。
重要提示:如果确认信息未能及时到达,消息可以重新发送(可能使用不同的容器)。各方必须自行做好准备,并存储最近收到的消息的标识符(并忽略重复消息,而不是重复操作)。为了避免标识符被永久存储,存在利用消息标识符单调性的特殊垃圾回收消息。
如果发送队列溢出,或者消息在队列中停留超过 10 分钟,服务器将忽略这些消息。如果服务器缓冲区空间不足(例如,由于严重的网络问题导致大量连接断开),这种情况发生得更快。
HTTPS
要通过 HTTPS 建立连接,只需使用TLS URI 格式即可。其余步骤与普通 HTTP相同。
URI格式
连接到纯 WebSocket 和 HTTP 端点时必须使用的 URI 格式如下:
http://X.X.X.X:80/api(w)(s)
以下 URI 仅可用于 HTTP 和安全 WebSocket 端点(不可用于普通 WebSocket 连接):
http://(name)(-1).web.telegram.org:80/api(w)(s)(_test)
w当需要 CORS 标头才能从浏览器连接时,会添加此标志。
此s标志启用 WebSocket API。域版本中的占位符指定要连接的域控制器 ID
:name
- pluto=> DC 1
- venus=> DC 2
- aurora=> DC 3
- vesta=> DC 4
- flora=> DC 5
-1可以将此标志附加到域控制器 (DC) 名称,以提高每个主机名同时请求的最大限制。当连接到 URL 的域版本时,此
标志_test指定必须连接到测试 DC。
TLS URI格式
连接到 HTTPS 和 WSS 端点时,只能通过端口 443 使用域名 URI:
https://(name)(-1).web.telegram.org:443/api(w)(s)(_test)
有关占位符的说明,请参阅URI 格式。
示例实现:tdlib、MadelineProto(客户端)、MTProxy(服务器端)。