博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
长连接API小心“窜包”问题
阅读量:6799 次
发布时间:2019-06-26

本文共 1060 字,大约阅读时间需要 3 分钟。

原文地址:

有时候,我们以API的方式为客户提供服务,如果此时你提供的API采用TCP长连接,而且还使用了TCP接收超时机制(API一般都会提供设置超时的接口,例如通过setsockopt设置SO_RCVTIMEO),那你可能需要小心下面这种情况(这里姑且称之为“窜包”,应用程序没有将应答包与请求包正确对应起来):

如果某一笔以TCP接收超时(例如设置为3秒)返回客户,此时客户继续使用该链接发送第二个请求,此时后者就有可能收到前一笔请求的应答(前一笔的应答在3秒后才到达),倘若错误的将此应答当做后者的应答处理,那就可能会导致严重的问题。如果网络不稳定,或者后台处理较慢,超时严重,其中一笔请求应答窜包了,很可能导致后续多个请求应答窜包。例如网上常见的抽奖活动,第一个用户中了一个iPad,而第二个用户在后台中仅为一个虚拟物品,若此时出现窜包,那第二个用户也会被提示中了iPad。

这个问题,初看起来最简单的解决办法就是:一旦发现有请求超时,就断开并重新建立连接,但这种方案理论上是不严谨的,考虑下面这种情况:

1)应答超时的原因是因为应答包在网络中游荡(例如某个路由器崩溃等原因,这类在网络中游荡的包,俗称迷途的分组);

2)API在检测到超时后,断开并重新建立的连接的IP和Port与原有连接相同(新连接为被断开连接的化身);

3)在新连接建立后,立即发送了一个新的请求,但随后那个迷途的应答包又找到了回家的路,重新到达,此时新连接很有可能将这个不属于自己的包,当做第二个请求的应答(该包的TCP Sequence恰好是新连接期望的TCP Sequence,这种情况是可能的)。

注:正常情况下,TCP通过维持TIME_WAIT状态2MSL时间,以避免因化身可能带来的问题。但是在实际应用中,我们可以通过调整系统参数,或者利用SO_LINGER选项使得close一个连接时,直接到CLOSE状态,跳过TIME_WAIT状态,又或者利用了端口重用,这样就可能会出现化身。

在实际应用中,上面这种情况基本不会发生,但是从理论上来说,是可能的。

再仔细分析,就会发现这个问题表面上看是因为“窜包”导致,但本质原因是程序在应用层没有对协议包效验。例如另外一种情况:A、B两个客户端与Server端同时建立了两个连接,如果此时Server端有BUG,错将A的应答,发到B连接上,此时如果没有效验,那同样会出现A请求收到B应答的情况。

所以这个问题解决之道就是:在应用层使用类似序列号这类验证机制,确保请求与应答的一一对应。

转载地址:http://bfuwl.baihongyu.com/

你可能感兴趣的文章
static_cast与dynamic_cast转换
查看>>
libevent2的hello world程序 —— 字符大写服务器
查看>>
LINQ简记(2):重要概念
查看>>
jQuery 1.6 源码学习(二)——core.js[2]之extend&ready方法
查看>>
[WPF疑难] 继承自定义窗口
查看>>
WebRTC网关服务器单端口方案实现
查看>>
018 easygui的使用
查看>>
iphone 开发h5 踩过的坑
查看>>
微信支付demo集
查看>>
python读取json的工具jsonreader | the5fire的技术博客
查看>>
Sharepoint学习笔记—习题系列--70-576习题解析 -(Q99-Q101)
查看>>
转oracle 学习 - 表空间
查看>>
百度地图显示多个标注点
查看>>
robots.txt的介绍和写作
查看>>
11个实用jQuery日历插件
查看>>
MySQL slave状态之Seconds_Behind_Master
查看>>
国内外开源与 SaaS ,团队协作平台、项目管理工具整理
查看>>
oracle字符集查看修改
查看>>
[Leetcode] Container With Most Water
查看>>
查看版本信息的命令
查看>>