3

私は現在、ネットワークを使用するプロジェクトに取り組んでいます。構造体を送信する必要があります

    struct Header
    {
     uint32_t   magic;
     uint32_t   checksum;
     uint32_t   timestamp;
     uint16_t   commandId;
     uint16_t   dataSize;
    };

    struct Packet
    {
     struct Header  header;
     char       data[128];
    };

TCPを使用して1つのソケットから別のソケットに構造体パケットを送信しようとしています。私はそのような私の構造を送ろうとしました

      send(socket, &my_struct, sizeof(my_struct), 0);

しかし、それは機能していないので、構造体を文字にシリアル化しようとしました*

unsigned char               *Serialization::serialize_uint32(unsigned char *buffer, uint32_t arg)
{
 buffer[3] = (arg >> 24);
 buffer[2] = (arg >> 16);
 buffer[1] = (arg >> 8);
 buffer[0] = (arg);
 return (buffer + sizeof(uint32_t));
}

unsigned char               *Serialization::serialize_uint16(unsigned char *buffer, uint16_t arg)
{
 buffer[1] = (arg >> 8);
 buffer[0] = (arg);
 return (buffer + sizeof(uint16_t));
}

    unsigned char                           *Serialization::deserialize_uint32(unsigned char *buffer, uint32_t *arg)
    {
      memcpy((char*)arg, buffer, sizeof(uint32_t));
      return (buffer + sizeof(uint32_t));
    }

    unsigned char                           *Serialization::deserialize_uint16(unsigned char *buffer, uint16_t *arg)
    {
     memcpy((char*)arg, buffer, sizeof(uint16_t));
     return (buffer + sizeof(uint16_t));
    }

クライアントが構造体を単純に送信した場合でも、サーバー側で読み取ったときにヘッダーデータが破損しているデータが破損しているのはなぜですか?

クライアント送信ループ

    TcpSocket                     tcp;
    Packet                        p;
    std::stringstream             ss;
    int                           cpt = 0;
    int                           ret = 0;
    char                          *serialized;

    tcp.connectSocket("127.0.0.1", 4242);
    while (getchar())
    {
      ss.str("");
      ss.clear();
  ss << cpt++;
  p.header.magic = 0;
  p.header.checksum = 1;
  p.header.timestamp = 2;
  p.header.commandId = 3;
  p.header.dataSize = ss.str().length();
  memset(p.data, 0, 128);
  memcpy(p.data, ss.str().c_str(), ss.str().length());
  serialized = new char[sizeof(Header) + ss.str().length()];
  bzero(serialized, sizeof(Header) + ss.str().length());
  Serialization::serialize_packet(serialized, p);
  hexDump("serialized", serialized+1, sizeof(Header) + ss.str().length());
  ret = tcp.write(serialized+1, sizeof(Header) + ss.str().length());
}

サーバー受信ループ:(select()による関数呼び出し)

  buff = new char[bav];
  socket->read(buff, bav);
  hexdump("buff", buff, bav);

socket-> read():

    int                     TcpSocket::read(char *buff, int len)
    {
      int                   ret;

      ret = recv(this->_socket, buff, len, 0);
      return (ret);
    }

私がそれらのプログラムを実行するとき:

    ./server
    [Server] new connexion :: [5]
    recv returns : 17
    buff serialized:
      0000  00 00 00 00 14 00 00 00 1c 00 00 00 1a 00 00 00  ................
      0010  1b

    ./client
    serialized data:
      0000  00 00 00 00 00 00 01 00 00 00 02 00 03 00 01 30  ...............0
      0010  00
    send returns : 17
4

3 に答える 3

5

したがって、これは間違っており、間違いなくエラーが発生します。

buff = new char[bav];
socket->read(buff, bav);
hexdump("buff", buff, bav);
socket->read() :

int TcpSocket::read(char *buff, int len)
{
    return recv(this->_socket, buff, len, 0);
}

からの戻り値はrecv()無視してはなりません。

差出人man 2 recv

戻り値
     これらの呼び出しは、受信したバイト数を返します。エラーの場合は-1を返します。
     発生した。

     TCPソケットの場合、戻り値0は、ピアが半分を閉じたことを意味します
     接続の側。

それで、あなたは何バイトを受け取りましたか?からの結果を破棄した場合、それを判断することは不可能ですrecv()。失敗したかもしれrecv()ませんが、戻り値をチェックしないとわかりません。多分それはあなたのバッファの一部をいっぱいにしただけです。 からの戻りコードを確認する必要がありますrecv() これは、TCPを使用するプログラムを作成するときに人々が犯す最大のエラーです。

次の場合を処理するには、コードを変更する必要があります。

  1. recv()呼び出しによってバッファが完全にいっぱいになる場合があります。

  2. 呼び出しによって、recv()バッファが部分的にいっぱいになる場合があります。

  3. 呼び出しはrecv()0を返す場合があり、送信者が接続をシャットダウンしたことを示します。

  4. システムコールによって中断されたため、呼び出しrecv()が示される場合があります。EINTR

  5. 送信者が突然接続を閉じたか、消えたために、呼び出しrecv()が示される場合があります。ECONNRESET

  6. recv()呼び出しで他のエラーが発生する可能性があります。

注意:TCPを使用する場合、 16バイトであるからsend()といって、他のピアがrecv()16バイトになるとは限りません。チャンクに分割される可能性があります。TCPはストリームプロトコルです。UDPとは異なり、隣接するデータのチャンクは任意に結合または分割できます。

于 2012-12-28T00:35:00.060 に答える
2
  1. 毎回下位8ビットのみをマスクする必要があります。

    buffer[3] = (arg >> 24) & 0xff;
    buffer[2] = (arg >> 16) & 0xff;
    buffer[1] = (arg >> 8) & 0xff;
    buffer[0] = (arg) & 0xff;
    
  2. デシリアライズするときにも同じようにします

于 2012-12-27T22:03:22.180 に答える
0

もし私があなただったら、私は車輪の再発明をしませんでした。あなたが探している目的のために、十分に文書化されテストされたライブラリ/プロトコルがたくさんあります。私の頭に浮かぶ小さなリスト:

于 2012-12-27T23:12:29.817 に答える