
*实际上,我们只会编写该协议的原型。
也许您遇到过类似的情况-坐在您最喜欢的信使中,与朋友聊天,进入电梯/隧道/马车,互联网似乎仍然存在,但是什么也发不出去? 有时,您的通信提供商错误地配置了网络,并且50%的数据包消失了,也没有任何作用。 也许您现在正在考虑-嗯,您可能可以以某种方式做些什么,以便在连接不良的情况下仍可以发送所需的一小段文字? 你并不孤单。
图片来源在本文中,我将讨论实现基于UDP的协议的想法,在这种情况下可以提供帮助。
TCP / IP问题
当我们的(移动)连接较差时,很大一部分数据包开始丢失(或者延时很长),TCP / IP协议可能会认为这是网络拥塞的信号,如果一切正常,一切都会开始缓慢工作一般而言。 建立连接(尤其是TLS)需要发送和接收多个数据包并不会增加喜悦,即使很小的损失也会严重影响其操作。 在建立连接之前,它通常还需要访问DNS –还有两个额外的数据包。
总而言之,连接不良的典型基于TCP / IP的REST API的问题:
- 对数据包丢失的响应不良(速度降低,超时时间过长)
- 建立连接需要交换数据包(+3个数据包)
- 通常,您需要“额外” DNS查询来查找IP服务器(+2个数据包)
- 经常需要TLS(最少+2个数据包)
总的来说,这意味着仅用于连接服务器,我们需要发送3-7个数据包,并且丢失率很高,连接可能要花费大量时间,而我们甚至还没有发送任何内容。
实施思路
这个想法是这样的:我们只需要发送一个UDP数据包到服务器的预先连接的IP地址,其中包含必要的授权数据和消息文本,然后得到答案。 所有数据都可以额外加密(这不在原型中)。 如果答案没有在一秒钟内到达,则我们认为请求已丢失,请尝试再次发送。 服务器应该能够删除重复的消息,因此重新发送不会造成问题。
生产就绪实施的可能陷阱
以下内容(绝不是全部)是您在“战斗”条件下使用类似内容之前需要考虑的事项:
- 提供商可以“切断” UDP-您需要能够通过TCP / IP工作
- UDP与NAT不友好-通常很少(〜30秒)时间来响应客户端请求
- 服务器必须能够抵抗攻击 -您需要确保响应数据包不超过请求数据包
- 加密很困难,而且如果您不是安全专家,则几乎没有机会正确实施加密
- 如果您错误地设置了重传间隔(例如,而不是每秒重试一次,而又不停止尝试重试一次),那么您所做的可能比TCP / IP差很多
- 由于缺乏UDP反馈和无休止的重试,更多的流量可能开始流向您的服务器
- 服务器可以有多个IP地址,并且它们可以随时间变化,因此您需要能够更新缓存(Telegram运作良好:))
实作
我们将编写一个服务器,该服务器将通过UDP发送响应,并向响应中发送到达它的请求的编号(该请求看起来像“ request-ts消息文本”),以及接收响应的时间戳:
现在最棘手的部分是客户。 我们将一次发送一条消息,并等待服务器响应后再发送下一条消息。 我们将发送当前时间戳和一条文本-时间戳将用作请求标识符。
功能代码:
func send(conn *net.UDPConn, requestID int64, resCh chan udpResult) { for {
我还基于(或多或少)标准REST实现了相同的事情:使用HTTP POST,我们发送相同的requestT和消息文本,并等待响应,然后转到下一个。 上诉是通过域名提出的,系统中没有禁止DNS缓存。 没有使用HTTPS来使比较更真实(原型中没有加密)。 超时设置为15秒:TCP / IP已经转发了丢失的数据包,用户很可能不会等待超过15秒。
测试结果
在测试原型时,会测量以下内容(全部以
毫秒为单位 ):
- 第一响应时间(第一)
- 平均响应时间(平均)
- 最大响应时间(最大)
- H / U-“ HTTP时间” /“ UDP时间”的比率-使用UDP时延迟减少了多少倍
发出了100个系列的10个请求-我们模拟了一种情况,当您只需要发送少量消息时,并且在正常的Internet(例如,地铁中的Wi-Fi或街道上的3G / LTE)可用之后。
测试的通讯类型:
- 在网络链接调节器中配置“非常严重的网络”(10%丢失,500 ms延迟,1 Mbps)-“非常严重”
- EDGE,冰箱中的电话(“电梯”)-冰箱
- 边缘
- 3G
- LTE
- 无线上网
结果(以毫秒为单位):

(
CSV格式相同 )
结论
以下是可以从结果中得出的结论:
- 除了LTE异常外,发送第一个消息的差异越大,连接越差(平均快2-3倍)
- 随后通过HTTP发送消息的速度并不慢-平均慢了1.3倍,但是在稳定的Wi-Fi上根本没有区别
- 基于UDP的响应时间要稳定得多,这可以通过最大延迟间接看到-也减少了1.4-1.8倍
换句话说,在适当的(“不良”)条件下,我们的协议会更好地工作,尤其是在发送第一个消息时(通常这就是所有需要发送的消息)。
原型实现
原型发布在github上 。 不要在生产中使用它!
在电话或计算机上启动客户端的命令:
instant-im -client -num 10
。 服务器仍在运行:)。 首先必须在第一个答案的时间以及最大延迟时查看。 所有这些数据都打印在末尾。