我正在编写一个小应用程序,它基本上来回交换XML。我有一个基于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无论如何都不应该受到责备,因为模拟器上的执行很好。请注意0
处的maxLength
表示“无限”缓冲区。
有没有人知道造成这种情况的原因是什么?
答案 0 :(得分:2)
这表明您将TCP数据包的接收与XML消息的完成混淆。无法保证TCP数据包将以XML消息边界结束。 GCDAsyncSocket是一个低级库,可以与TCP进行对话,而不是XML。
当您收到每个数据包时,您有责任将其连接到NSMutableData
,然后决定何时有足够的数据处理它。如果您的协议在每条消息之后关闭连接,那么您可以读取直到连接关闭。如果没有,那么你将不得不处理一个事实,即给定的数据包甚至可能包含下一条消息。您必须充分解析数据以确定边界的位置。
答案 1 :(得分:1)
解决方案是,当未指定时,AsyncSocket
查看下一行返回。当数据包终止时,它确实返回该行。我正在使用(sock
是我的GCDAsyncSocket对象)
[sock readDatawithTimeout:-1 tag:0]
但后来搬到了
[sock readDataToData:[msgTerm dataUsingEncoding:NSUTF8StringEncoding]
withTimeout:-1
tag:0]
其中msgTerm
是外部常量NSString,定义为“\ r \ n \ r \ n”,并在客户端和服务器源之间共享。这有效地避免了结束数据包的行返回问题。
关于此解决方案的另一个注意事项:因为我使用的是类似SOAP的协议,所以空格不是问题。但是,如果你的终结空白行很有气质,你可以使用像[incomingDecodedNsstringMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
这样的方法来清理它。
答案 2 :(得分:0)
看了GCDAsyncSocket
的代码,我说它完全有可能存在错误。例如,如果您正在阅读安全套接字,则在iPhone上使用cfsocket机制而不是普通的Unix风格文件描述符,并且作者可能会对套接字何时关闭做出无效假设。由于您有源代码,我尝试使用调试器逐步执行它以查看文件末尾是否过早被标记。
TCP是基于流的协议。从理论上讲,底层IP协议的数据包大小应该没什么区别,但是如果你足够快地读取套接字,你可能会把你的数据放在IP数据包大小的块中,特别是如果IP堆栈以某种方式调整内存使用(猜猜在这里!)。