5

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

コールバックで、次のことを行います。

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

}

つまり、すべてが1つのアトミックペイロードとして入ってくるのです。おそらくこれは、Erlang {packet、4}の動作方法が原因です。そうだといいのですが。それ以外の場合、readDataToLengthのポイントは何ですか?クライアントでメッセージの長さを事前に知る方法はないので、そのメソッドを使用するための良いユースケースは何ですか?

4

1 に答える 1

1

Erlang側からの送信方法にもよると思います。このオプション{packet, 4}は、プレフィックスが4バイトの長さの各データパケットを送信します。4Erlangでの各送信操作では、長さのプレフィックスが付いた1つのパケットが送信されます(たとえば、長さの最大サイズは2 Gbです)。Erlangドキュメントの関連部分は、を使用してソケットオプションを設定するinet:setopts/2ためのものです。

データは、これまでにソケットから読み取られた累積データの合計だと思います。そのデータにパケット全体が含まれている場合は問題ありません。ただし、そうでない場合はreadDataToLength、残りのデータを使用して、ソケットからのブロックされた読み取りを続行することをお勧めします。

于 2011-07-22T07:42:57.933 に答える