Ad

How To Recieve A Buffer Of Ints And Strings From A Client , And Store Them Right? (cpp Server , Python Client)

I have a simple cpp server which receives a char * buffer from a python client and unpacks it in order to use the data. the python client sends a buffer which includes 2 "different" data types - string and int. the buffer should look like this - buffer representation

which means if the client wants to send the message code 200, and the data "ok", he would have to send the buffer [2002ok]. But I have decided that the client would send the buffer as chars.

so, the buffer would look like this- [Èok]

(È = 200's ascii value, = 2's ascii value) (edit: I don't know why, but the ASCII value of 2 cannot be shown here..)

The problem is, That when I unpack the 3 parts of the buffer, they are somehow distorted.

here is my client side (Python):

msg = chr(200) + chr(0) + chr(0) + chr(0) + chr(2) + "ok"
print(">>>>" + (msg)) 
sock.send((msg.encode()))

and here is my server side(CPP):

           uint8_t  msgCode = helpMe.getCode(client_socket);
           std::cout << "The message code is " << static_cast<unsigned int>(msgCode) << std::endl;
           int DataLen = helpMe.getLength(client_socket);
           std::string StrData = helpMe.getString(client_socket, DataLen);

Here are the "Helper" functions I used (unpacking the data):



using std::string;

uint8_t Helper::getCode(SOCKET sc)
{
    uint8_t code;
    getPartFromSocket(sc, reinterpret_cast<char*>(&code), sizeof(code), 0);
    return code;
}

uint32_t Helper::getLength(SOCKET sc)
{
        uint32_t length;
        getPartFromSocket(sc, reinterpret_cast<char*>(&length), sizeof(length), 0);
        return length;
}

std::string Helper::getString(SOCKET sc, size_t length)
{
    std::string s(length + 1, 0);
    getPartFromSocket(sc, (char*)s.data(), length, 0);
    // possible since C++17   ^
    return s;
}

void Helper::getPartFromSocket(SOCKET sc, char * buffer, size_t bytesNum, int flags)
{
    if (bytesNum == 0)
    {
        return;
    }

    int res = recv(sc, buffer, bytesNum, flags);

    if (res == INVALID_SOCKET)
    {
        std::string s = "Error while recieving from socket: ";
        s += std::to_string(sc);
        throw std::exception(s.c_str());
    }

}

the client seems to work fine - it's output is:

È ok

but the server's output, which is supposed to be -

The message code is 200

is actually

The message code is ├

Where is my mistake? Thanks, M.

Ad

Answer

You should change the way you receive data:

void Helper::getPartFromSocket(SOCKET sc, char* buffer, size_t bytesNum, int flags);

instead of internally creating an array. Then you can do:

uint8_t Helper::getCode(SOCKET sc)
{
    uint8_t code;
    getPartFromSocket(sc, reinterpret_cast<char*>(&code), sizeof(code), 0);
    return code;
}
uint32_t Helper::getLength(SOCKET sc)
{
    uint32_t length;
    getPartFromSocket(sc, reinterpret_cast<char*>(&length), sizeof(length), 0);
    return length;
}
std::string Helper::getString(SOCKET sc, size_t length)
{
    std::string s(length, 0);
    getPartFromSocket(sc, s.data(), length, 0);
    // possible since C++17   ^
    return s;
}

i. e. you write the data directly to where it shall be placed. At the same time, you solve your memory leak issue...

Problem remains with endianness... You obviously write big endian on python side, but as is shown above, you'll (most likely – it's machine dependent, but big endian machines got very rare these days...) read little endian. To get independent of machine's byte order on C++ side, too, you could modify the code as follows:

uint32_t length = 0
for(unsigned int i = 0; i < sizeof(length); ++i)
{
    uint8_t byte;
    getPartFromSocket(sc, reinterpret_cast<char*>(&byte), sizeof(byte), 0);
    // little endian tranmitted:
    // length |= static_cast<uint32_t>(byte) << 8*i;
    // big endian transmitted:
    length |= static_cast<uint32_t>(byte) << 8*(sizeof(length) - (i + 1));
    // simpler: just adjust loop variable; = 1, <= sizeof            ^
}
return length;

Edit: some remarks from the comments, as these have been moved away:

Well, actually, there's already a function doing this stuff: ntohl (thanks, WhozCraig, for the hint), so you can get it much easier:

uint32_t length;
getPartFromSocket(sc, reinterpret_cast<char*>(&length), sizeof(length), 0);
return ntohl(length);

Another problem spotted during discussion, this time on python side:

sock.send((msg.encode()))

encode by default delivers an utf-8-encoded string, which is certainly not what we want in this case (200 will be converted to two bytes). Instead we need to use local machine's encoding (on a windows host, quite likely cp1252 for western Europe or cp1250 for central and eastern Europe).

Ad
source: stackoverflow.com
Ad