长连接API小心“窜包”问题

本文探讨了在使用TCP长连接提供API服务时可能出现的窜包问题,并提出了解决方案。窜包可能导致请求与应答对应错误,尤其是在网络不稳定的情况下。文章建议在应用层引入序列号等验证机制来确保数据包的正确对应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://pananq.com/index.php/2011/07/31/

有时候,我们以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应答的情况。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值