MTProto移动协议关于消息的服务消息
收据确认
几乎所有消息(除少数纯粹的服务消息以及协议中用于创建授权密钥的纯文本消息外)的接收都必须得到确认。这需要使用以下服务消息(无需确认):
msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck;
服务器通常使用 RPC 响应来确认收到来自客户端的消息(通常是 RPC 查询)。如果响应需要很长时间才能收到,服务器可能会先发送接收确认,稍后再发送 RPC 响应本身。
通常情况下,客户端会通过在下一个 RPC 查询中添加确认信息来确认收到服务器的消息(通常是 RPC 响应),前提是该确认信息发送时间不太晚(例如,在收到服务器消息后 60-120 秒内生成)。但是,如果长时间没有理由向服务器发送消息,或者服务器返回的未确认消息数量过多(例如超过 16 条),则客户端会单独发送确认信息。
每个构造函数最多允许 8192 个 ID。
忽略错误消息的通知
在某些情况下,服务器可能会通知客户端其收到的消息因某种原因被忽略。请注意,只有在服务器正确解码消息后,才能生成此类通知。
bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;
这里,error_code 还可以取以下值:
- 16:msg_id 过低(很可能是客户端时间错误;值得使用 msg_id 通知进行同步,并使用“正确”的 msg_id 重新发送原始消息,或者如果原始消息在客户端等待传输的时间过长,则将其包装在一个带有新 msg_id 的容器中)。
- 17:msg_id 过高(与前一个情况类似,需要同步客户端时间,并使用正确的 msg_id 重新发送消息)
- 18:msg_id 的低两位错误(服务器要求客户端消息 msg_id 能被 4 整除)
- 19:容器 msg_id 与先前接收到的消息的 msg_id 相同(这种情况绝对不能发生)
- 20:消息过旧,无法验证服务器是否收到过具有此 msg_id 的消息。
- 32:msg_seqno 过低(服务器已收到 msg_id 更低但 seqno 更高或相等且为奇数的消息)
- 33:msg_seqno 过高(类似地,存在 msg_id 较高但 seqno 较低或相等但为奇数的消息)。
- 34:预期收到偶数 msg_seqno(无关消息),但实际收到奇数。
- 35:预期收到奇怪的 msg_seqno(相关信息),但实际却收到了
- 48:服务器盐值错误(在这种情况下,收到的 bad_server_salt 响应包含正确的盐值,需要使用正确的盐值重新发送消息)
- 64:无效容器。
其目的是将 error_code 值分组(error_code >> 4):例如,代码 0x40 - 0x4f 对应于容器分解中的错误。
被忽略消息的通知不需要确认(即,无关紧要)。
重要提示:如果服务器上的 server_salt 值发生更改,或者客户端时间不正确,任何查询都会返回上述格式的通知。客户端必须检查其是否确实最近发送过带有指定 msg_id 的消息,如果是,则应根据 msg_id 和 server_salt 通知更新其时间校正值(客户端时钟与服务器时钟之间的差值)和服务器盐值,以便用于(重新)发送后续消息。同时,还必须使用更准确的 msg_id 和/或 server_salt 重新发送导致返回错误消息的原始消息。
此外,客户端可以根据 RPC 响应或包含 RPC 响应的容器的值来更新用于向服务器发送消息的 server_salt 值,前提是该 RPC 响应确实与最近发送的查询匹配。(如有疑问,最好不要更新,因为存在重放攻击的风险)。
请求消息状态信息
如果任何一方长时间未收到有关其外发邮件状态的信息,则可以明确地向另一方提出请求:
msgs_state_req#da69fb52 msg_ids:Vector long = MsgsStateReq;
每个构造函数最多允许 8192 个 ID。
查询结果包含以下信息:
关于消息状态的提示信息
msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
这里info是一个字符串,其中包含来自传入 msg_ids 列表的每条消息的一个字节的消息状态:
- 1 = 关于该消息一无所知(msg_id 太小,对方可能已经忘记了)
- 2 = 未收到消息(msg_id 在已存储的标识符范围内;但是,对方肯定没有收到过这样的消息)
- 3 = 未收到消息(msg_id 过高;但是,对方肯定还没有收到该消息)
- 4 = 已收到消息(请注意,此响应同时也是收到确认)
- +8 = 消息已确认
- +16 = 无需确认的消息
- +32 = 正在处理的消息中包含 RPC 查询,或者处理已完成
- +64 = 对已生成消息的内容相关回复
- +128 = 对方确切知道消息已被接收
此响应无需确认。它本身就是对相关 msgs_state_req 的确认。
请注意,如果突然发现对方遗漏了看似已发送给他们的消息,则不能使用相同的 msg_id 单独重新发送该消息。相反,可以将其包装在一个容器中,或者使用 msgs_state_req 检查消息状态。如果消息未被接收,则必须使用新的 msg_id 重新发送。
自愿沟通消息状态
任何一方均可自愿告知另一方另一方所发送消息的状态。
msgs_all_info#8cc0d131 msg_ids:Vector long info:string = MsgsAllInfo
本方已知的所有消息代码均已列出,但设置了 +128 和 +16 标志的消息代码除外。但是,如果设置了 +32 标志但未设置 +64 标志,则仍会传达消息状态。
此消息无需确认。
扩展自愿沟通状态一条消息
服务器通常使用此消息来响应重复的 msg_id,尤其是在已经生成对该消息的响应且响应内容较大的情况下。如果响应内容较小,服务器可能会直接重新发送响应。此消息也可以用作通知,而不是重新发送大型消息。
msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
第二个版本用于通知服务器上创建的消息(例如新消息通知),这些消息并非响应 RPC 查询而创建,并且已在一段时间前传输到客户端,但尚未得到确认。
目前status该值始终为零。未来可能会发生变化。
此消息无需确认。
明确请求重新发送消息
msg_resend_req#7d861a08 msg_ids:Vector long = MsgResendReq;
远程方会立即响应,重新发送请求的消息,通常使用与发送查询时相同的连接。如果至少有一条具有请求的 msg_id 的消息不存在、已被遗忘,或已被请求方发送(根据奇偶校验可知),则会为所有请求的消息返回 MsgsStateInfo,就好像 MsgResendReq 查询本身也是 MsgsStateReq 查询一样。
每个构造函数最多允许 8192 个 ID。