1

Qt を使用して、長さ優先の TCP メッセージを操作しようとしています。私は次の方法を持っています:

QByteArray con::read()
{
    QByteArray s;
    s = _pSocket->read(4);
    if (s.length() == 4) {
        int size = char_to_int32(s);
        s = _pSocket->read(size);
    }
    return s;
}

まあ、うまくいきません。最初の 4 バイトを読み取った後、すべてのデータを失ったようです。最初の読み取りは正常に機能しますが、read(size)何も返されません。これを解決する方法はありますか?

char_to_int32 は次のとおりです。

int char_to_int32(QByteArray s)
{
    int size = 0;
    size |= (s.at(0) << 24);
    size |= (s.at(1) << 16);
    size |= (s.at(2) << 8);
    size |= (s.at(3));
    return size;
}

編集 :

送信関数 (プレーン C):

int send(int connfd, const unsigned char* message, unsigned int size) {
    int c;
    unsigned char* bytes = (unsigned char*) malloc(4 + size);
    int32_to_char(size, bytes); // converts message size to 4 bytes
    memcpy(bytes + 4, message, size);
    c = write(connfd, bytes, 4 + size);
    free(bytes);
    if (c <= 0)
        return -1;
    else
        return 0;
}

ちなみに、_pSocket->readAll() を呼び出すと、4 バイトのサイズとメッセージ自体を含むパケット全体が読み取られます。

編集 :

void int32_to_char(uint32_t in, char* bytes) {
    bytes[0] = (in >> 24) & 0xFF;
    bytes[1] = (in >> 16) & 0xFF;
    bytes[2] = (in >> 8) & 0xFF;
    bytes[3] = in & 0xFF;
    return;
}
4

1 に答える 1

3

関数を使用しているためQByteArray QIODevice::read(qint64 maxSize)、エラーを正しく検出していない可能性があります。

この関数にはエラーを報告する方法がありません。空の QByteArray() を返すことは、現在読み取り可能なデータがないか、エラーが発生したことを意味します。

試してみるいくつかのこと:

  • qint64 QIODevice::read(char* data, qint64 maxSize)エラーを報告する を使用します。

    エラーが発生した場合 ... この関数は -1 を返します。

  • と に電話QIODevice::errorStringQAbstractSocket::errorて、何が問題なのかを調べてください。

    • QAbstractSocket::errorボーナス ポイントについては、エラー信号を聞いてください。
  • これが作成している新しいプロトコルである場合は、QDataStreamシリアライゼーションに使用してみてください。これは、長さのプレフィックスを自動的に処理し、プラットフォームに依存しません。異なるendiennessのchar_to_int32プラットフォームを混在させると壊れます。またint、 32 ビットであることが保証されていないため (少なくとも 16 ビットと定義されています) 、異なる OS またはコンパイラ間で壊れる可能性があります。

    • を使用できない場合QDataStreamは、少なくともhtons、ntohs ...関数を使用してください。

編集

hton/ntoh の使用法を示すサンプル コードを次に示します。32ビットであることが保証されているため、 uint32_tand notが使用されていることに注意してください。intまたmemcpy、エンコード/デコードでポインター キャストではなく、エイリアシングとアラインメントの問題を防ぐために使用しました (簡潔にするために、テスト関数でキャストを行いました)。

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

void encode(uint32_t in, char* out)
{
    /* Host to Network long (32 bits) */
    const uint32_t t = htonl(in);
    memcpy(out, &t, sizeof(t));
}

uint32_t decode(char* in)
{
    uint32_t t;
    memcpy(&t, in, sizeof(t));
    /* Network to Host long (32 bits) */
    return ntohl(t);
}

void test(uint32_t v)
{
    char buffer[4];
    printf("Host Input:  %08x\n", v);
    encode(v, buffer);
    printf("Network:     %08x\n", *((uint32_t*)buffer));
    printf("Host Output: %08x\n\n", decode(buffer));
}

int main(int argc, char** argv)
{
    test(0);
    test(1);
    test(0x55);
    test(0x55000000);
    return 0;
}
于 2012-04-30T22:25:37.217 に答える