简体   繁体   中英

Send & recv two structures by one socket

I have a structure:

struct one
{
    char name[10];
    int age;
};

struct two
{
    int X;
    int Y;
};

And now i want to send this structure for example first 'one', second 'two' and receive from socket.

But how receive it, if i dont know which structure i send (stuct 'one' or 'two' )?

You could add identifiers to the data you're sending:

enum StructID {
    STRUCT_ONE,
    STRUCT_TWO,
};

And send that before you send your data.

Uint16     id;
struct one dataOne;

id = STRUCT_ONE;
send(&id, sizeof(id));
send(&dataOne, sizeof(dataOne));

And on the receiving end:

char buffer[256];
unsigned nbRecv;

nbRecv = recv(buffer, sizeof(buffer));
if (nbRecv > sizeof(Uint16))
{
    char * p = buffer;

    Uint16 *pId = (Uint16*)p;
    p += sizeof(*pId);

    if (*pId == STRUCT_ONE)
    {
        struct one * pOne = (struct one *)p;
        p += sizeof(*pOne);

        if (nbRecv >= sizeof(*pId) + sizeof(*pOne))
        {
           // deal with pOne.
        }
        else
        {
           // Deal with too little data; pOne is incomplete....
        }
    }
    else if (*pId == STRUCT_TWO)
    {
        struct two * pTwo = (struct two *)p;
        p += sizeof(*pTwo);

        if (nbRecv >= sizeof(*pId) + sizeof(*pTwo))
        {
           // deal with pOne.
        }
        else
        {
           // Deal with too little data; pTwo is incomplete....
        }
    }
    else
    {
        // Error, unknown data.
    }
}
else
{
    // Deal with too little data....
}

Essentially you're defining a protocol at this point and the identifier is just a very simple "header" that exists to identify your data. A lot of protocols like this send the size of the data to follow as well so you can tell how much of the data there is before the next identifier/header.

Another common method besides integers is to send 4 ASCII characters, since they're easy to read when you are looking at raw data (Wireshark, hexdump, bytes in a debugger, etc). For your example I would suggest:

const char STRUCT_ONE_FOURCC[4] = { 'O', 'N', 'E', ' ' };
const char STRUCT_ONE_FOURCC[4] = { 'T', 'W', 'O', ' ' };

(Note, they're not strings per-say because they're not NULL terminated. They're fixed size character arrays.)

Note: in the above code I've left out most error checking and endian swap (to/from network byte order).

See Also:

You need to perform a serialization, adding an identifier. A (not so) simple solution would be:

template<int index>
struct serializable {
  static const int identifier = index;
}

struct A :
  public serializable<1>
{
  int a, b;
  char * serialize() { char *buffer = new char[sizeof (A) + sizeof (int)]; memcpy(buffer, this, sizeof(A)); }
  static A deserialize(const char *in) { return A{&in[sizeof(int)], &in[sizeof(int) * 2]}; }
}

You should define a protocol which you will use in your communication, don't send struct because of the different datatypes and memory alignment in a different systems. You can use xml instead, serialize your struct and send the xml string. Also check different libraries which are implementing the communication protocols over TCP. You can check the Apache Axis for instance. For manual serialization you can use boost::serialization and transform your struct to xml string.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM