通过NSStream发送时数据被截断
好的,我一整天都在这个bug中,我想我已经把它缩小到基本问题。通过NSStream发送时数据被截断
背景:
我的工作已经要求我写我自己的NSNetService
和NSNetServiceBrowser
版本通过蓝牙的iOS 5,这是一个伟大的冒险,允许卓悦的应用程序,因为我什么都不知道网络编程之前,我开始这个项目。我从各种示例项目和经典的Unix Network Programming教科书中学到了很多东西。我的实现主要基于Apple的DNSSDObjects
示例项目。一旦服务得到解决,我添加了代码来实际设备之间的连接。用CFStreamCreatePairWithSocketToHost(...)
获得NSInputStream
和NSOutputStream
。
问题:
我想通过此连接发送一些数据。数据由一个整数,几个NSStrings
和一个NSData
对象归档为NSKeyedArchiver
。 NSData
的大小约为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*/
}
}
NSStream
这样的网络会使用TCP连接。它可能会有所不同,但最大数据包大小通常在2k左右。由于你发送的消息实际上是160k,它将被分成多个数据包。
TCP把它抽象成只是一个数据流,所以你可以确定所有这些数据包将以正确的顺序接收。
然而,当只有数据的前2k已经到来很可能被称为stream:handleEvent:
委托方法 - 有没有办法为它知道,还有更精彩的未来,直到它。
请注意,方法read:maxLength:
没有升级,您将始终获得最大长度 - 在这种情况下,它似乎只会让您达到2k。
您应该计算实际的bytesReceived
,并将所有数据连接在一起,直到您收到您正在等待的总金额为止。
接收器如何知道它需要多少数据? - 您可能希望在发送数据之前设计协议,然后发送一个指定未来数据长度的已定义大小的整数。或者,如果您只是通过套接字发送一条消息,则可以在完成时关闭它,并且在套接字关闭后仅让接收器解除封存。
我认为你对此是正确的:)我会实现这个并看看它是怎么回事 – RyanM 2012-07-11 06:06:24
您似乎从self.inputStream中读取,但流传递到您的流:handleEvent:方法被称为aStream。他们是否以某种方式引用同一个对象?否则,我不确定你是否正在读取实际上有可用字节的数据流
好点..我不知道为什么我这样写。他们确实引用了相同的对象,而类只是一个NSInputStream的NSStreamDelegate – RyanM 2012-07-11 05:52:49
添加逻辑以实际计算您发送和接收的字节数。我怀疑你只是收到第一个缓冲区。您的'didReceiveData'方法应该累积来自多个缓冲区的数据。 – 2012-07-11 01:19:12