CocoaAsyncSocket并从套接字读取数据 [英] CocoaAsyncSocket and reading data from a socket

查看:324
本文介绍了CocoaAsyncSocket并从套接字读取数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的基于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]; 

现在在我的回调中,我只是执行以下操作:


$ b $ s $($)$($)$($)$($)$($)$($) {
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有什么意义?没有办法在客户端上预先知道一个消息的长度,那么在这个方法中使用该方法有什么好的用例?

解决方案

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



我猜数据是到目前为止,从插座读取的总累积数据。如果这些数据包含整个数据包,这很好。但是,如果没有,您可能希望继续使用 readDataToLength 与其余数据对套接字进行阻止读取。


On my TCP-socket based server, I send a packets over the stream where packets consist of a header specifying the number of bytes in the packet, followed by that number of bytes. For those familiar with Erlang, I'm simply setting the {packet, 4} option. On the iOS side, I have code that looks like this, assuming I want to figure out the size of the stream for this message:

[asyncSocket readDataToLength:4 withTimeout:-1 tag:HEADER_TAG];

That works fine and the following delegate method callback is invoked:

onSocket:didReadData:withTag:

I figure the next logical step is to figure out the size of the stream, and I do that with:

  UInt32 readLength;
  [data getBytes:&readLength length:4];
  readLength = ntohl(readLength);

After hard coding a string of 12 bytes on the server-side, readLength does indeed read 12 on the client also, so all is good so far. I proceed with the following:

 [sock readDataToLength:readLength withTimeout:1 tag:MESSAGE_TAG];

At this point though the callback onSocket:didReadData:withTag: is no longer invoked. Instead timeouts on the read are occurring, probably because I didn't handle the read properly, this delegate method gets invoked:

- (NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length 

so in total, the server is sending 16 bytes, a 4 byte header and a 12 byte binary stream.

I'm confident that the error is on how I'm using CocoaAsyncSocket. What's the right way to go about reading the rest of the stream after I figure out its size?

** UPDATE **

I changed my client and it seems to be working now. The problem is, I don't understand the point of readDataToLength with the new solution. Here's what I changed my initial read to:

[socket readDataWithTimeout:-1 tag:HEADER_TAG];

Now in my callback, I just do the following:

- (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];
    }

}

So everything is coming in as one, atomic payload. Perhaps this is because of the way Erlang {packet, 4} works. I hope it is. Otherwise, what's the point of readDataToLength? there's no way to know the length of a message in advance on the client, so what is a good use case to use that method in?

解决方案

It depends on how you send from the Erlang side, I suppose. The option {packet, 4} will send each data packet with a 4-byte length prefixed to it. Each send operation in Erlang will result in one packet being sent with it's length prefixed (the max size for length 4, for example, is 2 Gb). The relevant part of the Erlang documentation is for setting the socket options using inet:setopts/2.

I'm guessing the data is the total accumulated data read from the socket so far. If that data contains your whole packet, it's fine. But if not, you might want to continue to do a blocked read from the socket using readDataToLength with the remaining data.

这篇关于CocoaAsyncSocket并从套接字读取数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆