通过NSStream发送时数据被截断

问题描述:

好的,我一整天都在这个bug中,我想我已经把它缩小到基本问题。通过NSStream发送时数据被截断

背景:

我的工作已经要求我写我自己的NSNetServiceNSNetServiceBrowser版本通过蓝牙的iOS 5,这是一个伟大的冒险,允许卓悦的应用程序,因为我什么都不知道网络编程之前,我开始这个项目。我从各种示例项目和经典的Unix Network Programming教科书中学到了很多东西。我的实现主要基于Apple的DNSSDObjects示例项目。一旦服务得到解决,我添加了代码来实际设备之间的连接。用CFStreamCreatePairWithSocketToHost(...)获得NSInputStreamNSOutputStream

问题:

我想通过此连接发送一些数据。数据由一个整数,几个NSStrings和一个NSData对象归档为NSKeyedArchiverNSData的大小约为150kb,因此整个消息的大小约为160kb。通过连接发送数据后,我收到以下异常,当我试图解除存档...

Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: '*** -[NSKeyedUnarchiver initForReadingWithData:]: incomprehensible archive 

经过进一步的探索我注意到,接收到的数据仅约2KB ..被截断的消息,从而使档案“不可理解”。

潜在相关的代码:

,该数据发送到所有连接的设备

- (void) sendMessageToPeers:(MyMessage *)msg 
{ 
    NSEnumerator *e = [self.peers objectEnumerator]; 

    //MyMessage conforms to NSCoding, messageAsData getter calls encodeWithCoder: 
    NSData *data = msg.messageAsData; 

    Peer *peer; 
    while (peer = [e nextObject]) { 
    if (![peer sendData:data]) { 
     NSLog(@"Could not send data to peer.."); 
    } 
    } 
} 

在Peer类的方法,实际上到NSOutputStream

- (BOOL) sendData:(NSData *)data 
{ 
    if (self.outputStream.hasSpaceAvailable) { 
    [self.outputStream write:data.bytes maxLength:data.length]; 
    return YES; 
    } 
    else { 
    NSLog(@"PEER DIDN'T HAVE SPACE!!!"); 
    return NO; 
    } 
} 

NSStreamDelegate写入数据的方法处理流事件的方法(“接收”数据)

该代码中的缓冲区大小为32768 b/c,这就是我从中学到的任何示例代码中的内容。它是否是任意的?我试图将其改为200000,认为问题只是缓冲区太小,但它没有改变任何东西..我不认为我完全理解发生了什么。

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode 
{ 
    switch (eventCode) { 

    case NSStreamEventHasBytesAvailable: { 
     NSInteger  bytesRead; 
     uint8_t   buffer[32768];  // is this the issue? 
// uint8_t   buffer[200000]; //this didn't change anything 

     bytesRead = [self.inputStream read:buffer maxLength:sizeof(buffer)]; 
     if (bytesRead == -1) ...; 
     else if (bytesRead == 0) ...; 
     else { 
     NSData *data = [NSData dataWithBytes:buffer length:bytesRead]; 
     [self didReceiveData:data]; 
     } 
    } break; 

    /*omitted code for other events*/ 
    } 
} 
+0

添加逻辑以实际计算您发送和接收的字节数。我怀疑你只是收到第一个缓冲区。您的'didReceiveData'方法应该累积来自多个缓冲区的数据。 – 2012-07-11 01:19:12

NSStream这样的网络会使用TCP连接。它可能会有所不同,但最大数据包大小通常在2k左右。由于你发送的消息实际上是160k,它将被分成多个数据包。

TCP把它抽象成只是一个数据流,所以你可以确定所有这些数据包将以正确的顺序接收。

然而,当只有数据的前2k已经到来很可能被称为stream:handleEvent:委托方法 - 有没有办法为它知道,还有更精彩的未来,直到它。

请注意,方法read:maxLength:没有升级,您将始终获得最大长度 - 在这种情况下,它似乎只会让您达到2k。

您应该计算实际的bytesReceived,并将所有数据连接在一起,直到您收到您正在等待的总金额为止。

接收器如何知道它需要多少数据? - 您可能希望在发送数据之前设计协议,然后发送一个指定未来数据长度的已定义大小的整数。或者,如果您只是通过套接字发送一条消息,则可以在完成时关闭它,并且在套接字关闭后仅让接收器解除封存。

+0

我认为你对此是正确的:)我会实现这个并看看它是怎么回事 – RyanM 2012-07-11 06:06:24

您似乎从self.inputStream中读取,但流传递到您的流:handleEvent:方法被称为aStream。他们是否以某种方式引用同一个对象?否则,我不确定你是否正在读取实际上有可用字节的数据流

+0

好点..我不知道为什么我这样写。他们确实引用了相同的对象,而类只是一个NSInputStream的NSStreamDelegate – RyanM 2012-07-11 05:52:49