NSOutputStream或扭曲反应器合并TCP数据包
我正在为一个iPhone应用编写网络代码,这个应用需要和一个用Python Twisted做的后端进行交互。最近我遇到了一个问题,看起来我的NSOutputStream在发送数据时可能把数据重复发送了一遍,或者是Twisted在接收数据时把数据合并了。
我使用的是“苹果推荐”的TCP套接字风格,也就是非轮询的方式。
整个过程是这样的:
客户端
- 当有空间可用时(NSStreamEventHasSpaceAvailable):发送一包X字节的数据
- 当有空间可用时(NSStreamEventHasSpaceAvailable):再发送一包Y字节的数据
服务器
- Twisted接收到的包大小是(X + Y)字节
我确保在输出流状态是“NSStreamStatusWriting”时不发送数据。同时也确保在没有触发NSStreamEventHasSpaceAvailable事件时,客户端不允许发送数据。
有没有人知道可能是什么原因导致数据重复或合并的呢?Twisted的代码相对简单,使用了我协议中的标准dataReceived:
def dataRecieved(self, data): # do logic in order to decide how to handle data # ... # print of len(data) here reveals merged packet size
iOS的代码也很标准:
if (eventCode == NSStreamEventHasSpaceAvailable) { [outputStream write:[packet getData] maxLength:[packet getPacketSize]]; } // [packet getData] simply returns a standard UInt8 array. // [packet getPacketSize] returns the size of that array.
当上面的iOS代码连续调用两次(比如,发送两包数据一个接一个)时,Twisted的代码会报告合并后的数据大小。
提前感谢任何建议或意见。
1 个回答
我同意——我不应该指望缓冲区的边界一定会对上,但我想这还是跟可预测的行为有关。
在基于TCP的通信中,没有什么是可预测的;在你和远程主机之间,可能会有很多路由器、NAT边界、奇怪的代理等等,这些都会影响到看起来不太正常的行为。
说不定,甚至还有信鸽一字一句地传送你的数据包。
不过在现实世界中,行为通常是相对可预测的。但并不是总是这样,永远不会有100%的确定性,总是有可能某个地方的网络出现问题。
使用TCP时,至少可以保证数据包通常会按照发送的顺序被接收,前提是没有错误发生。当然,这也得假设中间的所有环节都正常工作,或者没有恶意行为(这意味着你得假设有时候数据会被损坏)。
即使有这样的保证,也没什么太大意义;你可能会收到10个数据包中的前8个……或者你可能收到所有的入站数据,但当你准备回复时,发现出站连接已经断了……
总之;你两边的缓冲算法必须假设缓冲区可能会以随机的方式填满,这样就会完全不匹配另一边的数据大小。虽然这不是严格要求的,但你的应用程序最好能防范随机的连接失败;防止缓冲区被截断、连接随机断开和数据损坏。
早期的字节长度字段和校验和会对你有帮助。不要轻易做假设!hjfdahjdas8y!$(&($@#&^@#)^&!@#&_[连接丢失]