CocoaAsyncSocket和从套接字读取数据

5
在我的基于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有什么意义呢?在客户端无法预先知道消息的长度,那么使用该方法的好处是什么?

1个回答

1

取决于你从 Erlang 端如何发送,我想。选项 {packet, 4} 会在每个数据包前添加一个 4 字节的长度前缀。Erlang 中的每个发送操作都会导致发送一个带有长度前缀的数据包(长度最大为 4,例如,为 2 Gb)。相关的 Erlang 文档是关于 使用 inet:setopts/2 设置套接字选项

我猜数据是到目前为止从套接字读取的总累积数据。如果该数据包含了整个数据包,那就没问题了。但如果不是,您可能需要继续使用 readDataToLength 从套接字阻塞读取剩余的数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接