在我的基于TCP套接字的服务器上,我通过流发送数据包,其中数据包由指定数据包中字节数的标头组成,后跟该字节数。对于那些熟悉Erlang的人,我只是设置{packet,4}选项。在iOS方面,我的代码看起来像这样,假设我想弄清楚此消息的流的大小:
[asyncSocket readDataToLength:4 withTimeout:-1 tag:HEADER_TAG];
工作正常,并调用以下委托方法回调:
onSocket:didReadData:withTag:
我认为下一个合乎逻辑的步骤是弄清楚流的大小,我这样做:
UInt32 readLength;
[data getBytes:&readLength length:4];
readLength = ntohl(readLength);
在服务器端硬编码一个12字节的字符串之后,readLength确实在客户端读取了12,所以到目前为止一切都很好。我继续以下内容:
[sock readDataToLength:readLength withTimeout:1 tag:MESSAGE_TAG];
此时虽然不再调用回调onSocket:didReadData:withTag:
。而不是读取超时,可能是因为我没有正确处理读取,这个委托方法被调用:
- (NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length
总的来说,服务器正在发送16个字节,一个4字节的头和一个12字节的二进制流。
我确信错误在于我如何使用CocoaAsyncSocket。在弄清楚它的大小后,读取其余流的正确方法是什么?
**更新**
我改变了我的客户,现在似乎正在运作。问题是,我不明白readDataToLength与新解决方案的关系。这是我将我的初步阅读改为:
[socket readDataWithTimeout:-1 tag:HEADER_TAG];
现在在我的回调中,我只是执行以下操作:
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
if (tag == HEADER_TAG) {
UInt32 readLength;
[data getBytes:&readLength length:4];
readLength = ntohl(readLength);
int offset = 4;
NSRange range = NSMakeRange(offset, readLength);
char buffer[readLength];
[data getBytes:&buffer range:range];
NSLog(@"buffer %s", buffer);
//[sock readDataToLength:readLength withTimeout:1 tag:MESSAGE_TAG];
} else if (tag == MESSAGE_TAG) {
//[sock readDataToLength:4 withTimeout:1 tag:HEADER_TAG];
}
}
所以一切都是原子有效载荷。也许这是因为Erlang {packet,4}的工作方式。我希望是的。否则,readDataToLength有什么意义?在客户端上无法预先知道消息的长度,那么使用该方法的好用例是什么?
答案 0 :(得分:1)
这取决于你从Erlang方面发送的方式,我想。选项{packet, 4}
将发送每个数据包,其长度为4字节长度。 Erlang中的每个发送操作将导致发送一个数据包,其长度为前缀(长度4
的最大大小,例如,为2 Gb)。 Erlang文档的相关部分适用于setting the socket options using inet:setopts/2
。
我猜测数据是到目前为止从套接字读取的总累积数据。如果该数据包含您的整个数据包,那很好。但如果没有,您可能希望使用readDataToLength
继续使用剩余数据从套接字执行阻止读取。