服务消息

服务消息

服务消息

服务消息

服务消息 :Telegram 应用程序服务消息

对 RPC 查询的响应

对 RPC 查询的响应通常包装如下:

rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;

这里req_msg_id是对方发送的消息的标识,包含一个RPC查询。这样,接收者就知道结果是对特定 RPC 查询的响应。同时,该响应作为对对方收到req_msg_id消息的确认。

请注意,还必须确认对 RPC 查询的响应。最常见的情况是,这与下一条消息的传输同时发生(可能附有一个容器,其中包含带有确认的服务消息)。

RPC 错误

响应任何 RPC 查询返回的结果字段也可能包含以下格式的错误消息:

rpc_error#2144ca19 error_code:int error_message:string = RpcError;
取消 RPC 查询
在某些情况下,Telegram 客户端不希望收到对已传输的 RPC 查询的响应,例如,因为响应结果很长,并且客户端由于链路容量不足而决定不接收它。简单地中断 TCP 连接不会有任何影响,因为服务器会在第一时间重新发送丢失的响应。因此,客户端需要一种方法来取消接收 RPC 响应消息,在实际接收到它之前实际确认它的接收,这将使服务器停止并防止它重新发送响应。但是,客户端在收到响应之前并不知道 RPC 响应的 msg_id;它唯一知道的是req_msg_id。即相关RPC查询的msg_id。因此,使

用了一个特殊的查询:

rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;
对此查询的响应作为包装在 rpc_result 中并需要确认的以下消息之一返回:

rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;
如果服务器不记得传入的 req_msg_id (例如,如果它已经被响应),则使用响应的第一个版本。如果在处理 RPC 查询时取消了响应(此时 RPC 查询本身仍被完全处理),则使用第二个版本;在这种情况下,也会返回相同的 rpc_answer_dropped_running 作为对原始查询的响应,并且这两个响应都需要客户端的确认。最终版本意味着 RPC 响应已从服务器的传出队列中删除,并将其 msg_id、seq_no 和长度(以字节为单位)传输到客户端。

请注意,rpc_answer_dropped_running 和 rpc_answer_dropped 作为服务器收到原始查询的确认(同一个,我们希望忘记的响应)。此外,与任何 RPC 查询一样,对 rpc_drop_answer 的任何响应都是对 rpc_drop_answer 本身的确认。

作为使用 rpc_drop_answer 的替代方法,可以在连接重置后创建一个新会话,并通过 destroy_session 删除旧会话。

与查询、更改和接收其他消息的状态相关的消息
请参阅移动协议:关于消息的服务消息

请求几种未来的盐

Telegram 客户端可以随时从服务器请求几个(1 到 64 之间)未来的服务器盐及其有效期。将它们存储在持久内存中后,客户端可以在将来使用它们来发送消息,即使它改变了会话(服务器盐附加到授权密钥而不是特定于会话)。

get_future_salts#b921bd04 num:int = FutureSalts;
future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt;
future_salts#ae500895 req_msg_id:long now:int salts:vector<future_salt> = FutureSalts;
客户端必须检查响应的 req_msg_id 是否与 get_future_salts 查询的 msg_id 一致。服务器最多返回 num 个未来的服务器盐(可能返回更少)。响应用作对查询的确认,本身不需要确认。

Ping 消息 (PING/PONG)
ping#7abe77ec ping_id:long = Pong;
响应通常返回到同一个连接:

pong#347773c5 msg_id:long ping_id:long = Pong;
这些消息不需要确认。Pong 仅在响应 ping 时发送,而 ping 可以由任何一方发起。

延迟连接关闭 + PING

ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;
像 ping 一样工作。此外,在收到此消息后,服务器将启动一个计时器,该计时器将在几秒钟后关闭当前连接 disconnect_delay ,除非它收到一条相同类型的新消息,该消息会自动重置所有先前的计时器。例如,如果客户端每 60 秒发送一次这些 ping,它可以设置 disconnect_delay 等于 75 秒。

请求销毁会话

电报客户端用来通知服务器它可能会忘记属于同一用户的不同会话的数据(即具有相同的 auth_key_id)。应用于当前会话的结果是未定义的。

destroy_session#e7512126 session_id:long = DestroySessionRes;
destroy_session_ok#e22045fc session_id:long = DestroySessionRes;
destroy_session_none#62d350c9 session_id:long = DestroySessionRes;

新会话创建通知

服务器通知纸飞机客户端必须创建一个新会话(从服务器的角度来看)来处理客户端消息。如果在此之后,服务器在同一个会话中接收到一个带有更小 msg_id 的消息,也会为这个 msg_id 生成类似的通知。不会为高 msg_id 值生成此类通知。

new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession
每次(重新)创建会话时,服务器都会生成 unique_id 参数。

此通知必须得到客户端的确认。例如,客户端必须了解实际上从服务器接收的长轮询通知流中存在“间隙”(用户可能在一段时间内未能接收到通知)。

请注意,服务器可以单方面销毁(关闭)任何现有电报客户端会话以及所有未决消息和通知,而不发送任何通知。例如,如果会话长时间处于非活动状态,并且服务器内存不足,则会发生这种情况。如果客户端在某个时候决定使用服务器已经忘记的旧会话向服务器发送新消息,则会生成这样的“新会话已创建”通知。客户应该优雅地处理这种情况。

容器

容器是包含若干其他消息的消息。用于使用 HTTP 甚至 TCP 或 UDP 协议同时传输多个 RPC 查询和/或服务消息的能力。一个容器只能被另一方作为一个整体接受或拒绝。

简单容器

一个简单的容器携带如下几条消息:

msg_container#73f1f8dc messages:vector message = Message Container;
这里的消息是指任何消息及其长度和msg_id:

message msg_id:long seqno:int bytes:int body:Object = Message;
bytes是正文序列化中的字节数。容器中的所有消息的 msg_id 必须低于容器本身的 msg_id。一个容器不需要确认,也不能携带其他简单的容器。当消息被重新发送时,它们可以以不同的方式组合到一个容器中或单独发送。

MTProto 容器有效负载有2^15字节或1020消息的限制,以先达到的限制为准。
客户端应将确认、状态请求和消息重发请求分组为三个单独的服务消息msgs_ack,每个服务消息最多有 8192 个 ID;这三个消息(+http_wait)不会包含在消息限制中。 msgs_state_reqmsg_resend_req1020

也允许空容器。它们被服务器使用,例如,当 http_wait 中指定的超时到期并且没有要传输的消息时响应 HTTP 请求。

示例实现。

邮件副本

在某些情况下,需要重新发送 msg_id 不再有效的旧消息。然后,它被包装在一个复制容器中:

msg_copy#e06046b2 orig_message:Message = MessageCopy;
一旦收到,消息就会被处理,就好像包装器不存在一样。但是,如果确定已收到消息 orig_message.msg_id,则不处理新消息(同时确认它和 orig_message.msg_id)。orig_message.msg_id 的值必须小于容器的 msg_id。

这时候不使用,因为旧消息可以包装在一个简单的容器中,结果相同。

打包对象

用于用其存档(gzipped)表示替换任何其他对象(或者更确切地说,其序列化):

gzip_packed#3072cfa1 packed_data:string = Object;
目前,它在 RPC 响应的主体(即,作为 rpc_result 的结果)中得到支持,并由服务器为有限数量的高级查询生成。此外,它还可用于将非服务消息(即 RPC 查询)从客户端传输到服务器。

HTTP 等待/长轮询

以下不需要确认的特殊服务查询(必须仅通过 HTTP 连接传输)用于使服务器能够在将来使用 HTTP 协议向客户端发送消息:

http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;
当接收到这样一条消息(或携带这样一条消息的容器)时,服务器要么等待max_delay几毫秒,然后如果会话中至少有一条消息排队(如果需要,将它们放入一个容器中,也可以添加确认);否则等待不超过max_wait毫秒,直到这样的消息可用。如果消息从未出现,则传输一个空容器。

该max_delay参数表示此会话的第一条消息与传输 HTTP 响应之间经过的最大毫秒数。该wait_after参数的工作原理如下:在收到特定会话的最新消息后,服务器会再等待wait_after几毫秒,以防有更多消息。如果没有其他消息,则传输结果(包含所有消息的容器)。如果出现更多消息,则wait_after计时器被重置。

同时,max_delay参数的优先级高于wait_after,且max_wait优先级高于max_delay。

此消息不需要响应或确认。如果通过 HTTP 传输的容器携带多个这样的消息,则行为未定义(实际上,将使用最新的参数)。

如果http_wait容器中没有,则使用默认值max_delay=0(毫秒)、wait_after=0(毫秒)和max_wait=25000(毫秒)。

如果客户端对服务器的 ping 需要很长时间,则将其设置max_delay为与 ping 时间大小相当的值可能是有意义的。

Telegram 应用程序服务消息,从 4.6 版开始,主要的 Telegram 客户端正在使用MTProto 2.0,如本文所述。MTProto v1.0(此处描述以供参考)已被弃用,目前正在逐步淘汰。

分享到 :