0

さて、私は一日中このバグに直面していて、根本的な問題に絞り込んだと思います。

バックグラウンド:

私は自分のバージョンを作成し、iOS 5でBluetooth経由のBonjourを許可する必要があるアプリに取り組んでいNSNetServiceますNSNetServiceBrowser。このプロジェクトを開始する前は、ネットワークプログラミングについて何も知らなかったので、これは素晴らしい冒険でした。私はさまざまなサンプルプロジェクトや古典的なUnixネットワークプログラミングの教科書から多くのことを学びました。私の実装は、主にAppleのDNSSDObjectsサンプルプロジェクトに基づいています。サービスが解決されたら、実際にデバイス間を接続するコードを追加しました。anNSInputStreamとanNSOutputStreamはで達成されCFStreamCreatePairWithSocketToHost( ... )ます。

問題:

この接続を介してデータを送信しようとしています。データは、整数、少数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メソッド

このコードのバッファサイズは32768b/ 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*/
  }
}
4

2 に答える 2

7

NSStreamそのようなネットワークを介してTCP接続を使用します。変動する可能性がありますが、最大パケットサイズは多くの場合約2kです。送信するメッセージは実際には160kであるため、複数のパケットに分割されます。

TCPはこれを抽象化してデータのストリームにするだけなので、これらすべてのパケットが正しい順序で受信されることを確認できます。

ただし、stream:handleEvent:デリゲートメソッドは、最初の2kのデータのみが到着したときに呼び出されている可能性があります。到着するまで、さらに多くのデータが到着していることを知る方法はありません。

この方法では、read:maxLength:常にその最大長が得られるとは限らないことに注意してください。この場合、最大2kしか得られないようです。

実際のをカウントアップし、bytesReceived待機している合計金額を受け取るまで、すべてのデータを連結する必要があります。

受信者はどのようにして必要なデータ量を知るのですか?–データを送信する前に、受信データの長さを示す定義されたサイズの整数を送信するようにプロトコルを設計することをお勧めします。または、ソケットを介してメッセージを1つだけ送信する場合は、終了時にメッセージを閉じるだけで、ソケットを閉じた後にのみ受信者にアーカイブを解除させることができます。

于 2012-07-11T01:55:08.940 に答える
1

self.inputStreamから読み取っているように見えますが、stream:handleEvent:メソッドに渡されたストリームはaStreamと呼ばれます。彼らはどういうわけか同じオブジェクトを参照していますか?そうでなければ、実際に利用可能なバイトがあるストリームを読んでいるかどうかわかりません

于 2012-07-11T01:18:07.683 に答える