iOS 数据包长度

Posted

技术标签:

【中文标题】iOS 数据包长度【英文标题】:iOS Packet Length 【发布时间】:2012-03-12 17:00:05 【问题描述】:

我正在编写一个小应用程序,该应用程序基本上来回交换 XML 和 SOAP。我有一个基于 OS X 的服务器和一个 iPad 客户端。我在客户端使用KissXML,在服务器上使用内置的 XML 解析器。我在两者上都使用GCDAsyncSocket 进行通信。

当我在 iPad 模拟器上测试我的应用程序时,会通过完整的 XML。一切正常。

但是,当我使用我的开发设备(实际的物理 iPad)时,其他一切都正常,但 XML 在第 1426 个字符之后终止。我已验证此错误发生在多台 iPad 上。

当我订阅 GCDAsyncSocket 上的传入数据包时,我使用 [sock readDataWithTimeout:-1 buffer:[NSMutableData new] bufferOffset:0 maxLength:0 tag:0]; 和以前只是一个简单的 [sock readDataWithTimeout:-1 tag:0]; 但两者都有相同的结果。似乎 GCDAsyncSocket 无论如何都不应受到责备,因为在模拟器上执行很好。请注意,maxLength 处的 0 表示“无限”缓冲区。

有人知道是什么原因造成的吗?

【问题讨论】:

字符 1426 或它周围的任何其他字符有什么特别之处吗?如果不使用 ARC,[NSMutableData new] 也可能会泄漏内存。考虑[NSMutableData data] 每次传输的数据不同,但总是在同一个地方终止,模拟器无问题;因此我推断某处的最大长度。附带说明一下,这些程序确实使用 ARC。 根据您的具体网络设置,MTU 通常在 1400-1500 左右。比这更长的消息会被分段并在单独的数据包中发送。当您在模拟器上运行时,服务器在同一台机器上,您没有使用物理网络,因此有效 MTU 更高,并且您不会变得碎片化。你确定你正确使用GCDAsyncSocket 吗?它可能预计您会反复调用readDataWithTimeout,而不仅仅是一次。 【参考方案1】:

1426 听起来很像 MTU(最大传输单元),它是您可以发送的最大 TCP 数据的大小。在不同的网络媒体和不同的配置上它的大小不同,但 1426 是很常见的。

这表明您将 TCP 数据包的接收与 XML 消息的完成混淆了。不能保证 TCP 数据包将在 XML 消息边界上结束。 GCDAsyncSocket 是一个低级库,它使用 TCP,而不是 XML。

当您收到每个数据包时,您有责任将其连接到NSMutableData,然后决定何时有足够的时间处理它。如果您的协议在每条消息后关闭连接,那么您可以阅读直到连接关闭。如果没有,那么您将不得不处理给定数据包甚至可能包含一些下一条消息的事实。您必须充分解析数据以确定边界在哪里。

顺便说一句,您的 Mac 的 MTU 很可能与您的 iPad 不同,这就是您在不同平台上看到不同行为的原因。

【讨论】:

【参考方案2】:

解决方案是,当未指定时,AsyncSocket 会查找下一行返回。当数据包终止时,它确实返回了该行。我正在使用(sock 是我的 GCDAsyncSocket 对象)

[sock readDatawithTimeout:-1 tag:0]

但后来搬到了

[sock readDataToData:[msgTerm dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0]

其中msgTerm 是定义为“\r\n\r\n”的外部常量 NSString,并在客户端和服务器源之间共享。这有效地规避了结束数据包的换行问题。

关于此解决方案的附加说明:因为我使用的是类似 SOAP 的协议,所以空格不是问题。但是,如果您对终止空白行有脾气,您可以使用[incomingDecodedNsstringMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] 之类的方法来清理它。

【讨论】:

【参考方案3】:

看过GCDAsyncSocket 的代码后,我会说它完全有可能存在错误。例如,如果您正在读取安全套接字,则在 iPhone 上使用 cfsocket 机制而不是普通的 Unix 样式文件描述符,并且作者可能对套接字何时关闭做出了无效的假设。既然你有源代码,我会尝试使用调试器单步执行它,看看文件结尾是否被过早标记。

TCP 是基于流的协议。从理论上讲,底层 IP 协议的数据包大小应该没有什么区别,但是如果您读取套接字的速度足够快,您很可能会以 IP 数据包大小的块的形式获取数据,特别是如果 IP 堆栈以某种方式针对内存使用进行了调整(在这里猜!)。

【讨论】:

以上是关于iOS 数据包长度的主要内容,如果未能解决你的问题,请参考以下文章

PING网络数据包为何只能65500

为啥数据报很少超过1500字节

简析 Golang IO 包

TCP 、UDP包的最大长度是多少?

IP包格式

UDP数据报的最小长度是多少 UDP数据报的