NSStream
TCP 接続を介して s を使用して 2 つの iOS デバイス間でデータを送信するようにアプリケーションをセットアップしました。
送信されるデータは、次の 2 つの部分で構成されます。
- 受信するメッセージ オブジェクトのサイズを示す整数
- メッセージ オブジェクト、一部
NSStrings
、およびNSData
NSKeyedArchiver でエンコードされたオブジェクト
問題:
- NSData オブジェクトが約 1.5Mb の場合、デコードしようとすると、理解できないアーカイブ例外が発生します。メッセージがあるはずの場所に続く 4 バイトを読み取ると、次のメッセージのサイズではなく、大きな数値が存在します。
- NSData オブジェクトが約 80Kb の場合、2 つのメッセージが正常にデコードされ、理解できないアーカイブ例外が発生します。
ある時点でデータの順序が乱れているように見えます... TCP の全体的な目的はデータを順序どおりに保つことですが。だから、私が問題に違いない!
関連コード
サーバ
sendData:
NSKeyedArchiver でエンコードされた Message オブジェクトが渡されます。短時間で 100 件程度のメッセージが呼び出される
// dataQueue is an NSMutableArray
- (void) sendData:(NSData *)data
{
int size = data.length;
NSData *msgSize = [NSData dataWithBytes:&size length:sizeof(int)];
if (self.outputStream.hasSpaceAvailable && (self.dataQueue.count == 0)) {
[self.dataQueue addObject:data];
[self.outputStream write:msgSize.bytes maxLength:msgSize.length];
}
else {
[self.dataQueue addObject:msgSize];
[self.dataQueue addObject:data];
}
}
//called by NSStreamDelegate method when space is available
- (void) hasSpaceAvailable
{
if (self.dataQueue.count > 0) {
NSData *tmp = [self.dataQueue objectAtIndex:0];
[self.outputStream write:tmp.bytes maxLength:tmp.length];
[self.dataQueue removeObjectAtIndex:0];
}
}
クライアント
streamHasBytes:
メッセージフラグメントを収集し、self.buffer に追加します。self.buffer の長さが、self.buffer の最初の 4 バイトで示されるメッセージの長さよりも大きくなると、Message オブジェクトが解析されます...
//Called by NSStreamDelegate method when bytes are available
- (void) streamHasBytes:(NSInputStream *)stream
{
NSInteger bytesRead;
uint8_t buffer[32768];
bytesRead= [stream read:buffer maxLength:sizeof(buffer)];
if (bytesRead == -1 || bytesRead == 0) //...err
@synchronized(self) { //added to test concurrency
[self.buffer appendBytes:buffer length:bytesRead];
}
[self checkForMessage];
}
- (void) checkForMessage
{
@synchronized(self) { //added to test concurrency
int msgLength = *(const int *)self.buffer.bytes;
if (self.buffer.length < msgLength) return;
//remove the integer from self.buffer
[self.buffer replaceBytesInRange:NSMakeRange(0, sizeof(int)) withBytes:NULL length:0];
//copy the actual message from self.buffer
NSData *msgData = [NSData dataWithBytes:self.buffer.bytes length:msgLength];
//remove the message from self.buffer
[self.buffer replaceBytesInRange:NSMakeRange(0, msgLength) withBytes:NULL length:0];
Message *theMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData];
[self.delegate didReceiveMessage:theMsg];
}
}
編集:
最初のメッセージの NSData オブジェクトが約 1.5Mb の場合、メッセージの合計サイズが約 1.6Mb の場合、クライアントは約 1.3Mb しか受信しないことに気付きました...これは理解できないことを説明しますアーカイブ エラー。すべてのデータが配信されないのはなぜですか?