在我的基于TCP套接字的服务器上,我通过流发送数据包,其中数据包由一个头部和指定数据包中字节数的标识组成。对于那些熟悉Erlang的人来说,我只是设置了{packet, 4}选项。在iOS端,我有这样的代码,假设我想知道此消息的流大小:
在服务器端硬编码了一个12字节的字符串后,readLength确实也在客户端读取了12,所以到目前为止一切都很好。我继续执行以下操作:
[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有什么意义呢?在客户端无法预先知道消息的长度,那么使用该方法的好处是什么?