简体   繁体   中英

Convert data to big endian

I'm using WinSock to send UDP packets to the server, I need to send the data in big endian. I'm not sure how to convert the byte order of my structure before sending.

I have a struct like this:

struct ConnectIn
{
    std::int64_t ConnectionID = 0x41727101980;
    std::int32_t Action = 0;
    std::int32_t TransactionID;

    ConnectIn(std::int32_t transactionID)
    {
        TransactionID = transactionID;
    }
};

And at the moment I'm sending like this:

ConnectIn msg(123);
int len = sizeof(msg);
int bytesSent = sendto(s, (char*)&msg, len, 0, (SOCKADDR*)&dest, sizeof(address));

How can I convert the byte order of msg to big endian before sending?

If you're curious, the data I'm sending is for the Bit Torrent UDP tracker protocol .

If you want to do this manually then what you do is swap each member individually. You convert the members from the host computer's byte ordering to the network's byte ordering. On Win32 htonll() is for 64-bit integers and htonl() is for 32-bit integers:

#include <Winsock2.h>

ConnectIn msg(123);

msg.ConnectionID = htonll(msg.ConnectionID);
msg.Action = htonl(msg.Action);
msg.TransactionID= htonl(msg.TransactionID);

Then you might also want to send the members individually, to avoid relying on the host system's struct layout. The Windows ABI doesn't insert any padding in this struct, but perhaps for some other struct you use it does. So here's the basic idea:

char buf[sizeof msg.ConnectionID + sizeof msg.Action + sizeof msg.TransactionID];
char *bufi = buf;

std::memcpy(bufi, &msg.ConnectionID, sizeof msg.ConnectionID);
bufi += sizeof msg.ConnectionID;
std::memcpy(bufi, &msg.Action, sizeof msg.Action);
bufi += sizeof msg.Action;
std::memcpy(bufi, &msg.TransactionID, sizeof msg.TransactionID);
bufi += sizeof msg.TransactionID;

int len = sizeof buf;
int bytesSent = sendto(s, buf, len, 0, (SOCKADDR*)&dest, sizeof(address));

Then on the receiving side you use the appropriate ntoh*() functions for 64-bit and 32-bit types to convert from the network's byte ordering to the receiving host's byte ordering.

Yes, the Network Byte Order (NBO) is Big Endian and so you need to find a way to send that structure on the web.

What you're currently doing won't work: you're sending the whole struct but the receiver may have a different endianness, padding and so on.
The easiest options are:

  • Sending each field with a protocol-defined layout
  • Third part libraries which handle serialization: Google Protobuf is one of the most common ones.

For the first option, there're some functions which take care of that in the Winsock2 library. These are:

  • (WSA)ntoh t (Network to Host t, where t can be short and unsigned )
  • (WSA)hton t (Host to Network t, where t can be short and unsigned )

WSA functions are a little bit different and Windows-only.


The Network Programming Guide
Winsock Reference

One option is converting each of the numbers individually

For GCC:

int32_t __builtin_bswap32 (int32_t x)
int64_t __builtin_bswap64 (int64_t x)

For MSVC:

unsigned short _byteswap_ushort(unsigned short value);
unsigned long _byteswap_ulong(unsigned long value);
unsigned __int64 _byteswap_uint64(unsigned __int64 value);

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