如何从客户端接收 int 和 string 的缓冲区,并正确存储它们? (cpp 服务器,python 客户端)

How to recieve a buffer of ints and strings from a client , and store them right? (cpp server , python client)

我有一个简单的 cpp 服务器,它从 python 客户端接收一个 char * 缓冲区并将其解压缩以使用数据。 python 客户端发送一个包含 2 "different" 数据类型的缓冲区——字符串和整数。 缓冲区应该是这样的 -

这意味着如果客户端要发送消息代码 200 和数据 "ok",他必须发送缓冲区 [2002ok]。 但我已经决定客户端将缓冲区作为字符发送。

所以,缓冲区看起来像这样- [Èok]

(È = 200的ascii值, = 2的ascii值) (编辑:我不知道为什么,但是这里不能显示 2 的 ASCII 值..)

问题是,当我解压缩缓冲区的 3 个部分时,它们以某种方式扭曲了。

这是我的客户端 (Python):

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

这是我的服务器端 (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);

以下是我使用的 "Helper" 函数(解压数据):



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());
    }

}

客户端似乎工作正常 - 它的输出是:

È ok

但是服务器的输出应该是 -

The message code is 200

实际上是

The message code is ├

我的错误在哪里? 谢谢,M.

您应该更改接收数据的方式:

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

而不是在内部创建一个数组。然后你可以这样做:

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;
}

我。 e.您将数据直接写入应放置的位置。同时,您解决了内存泄漏问题...

问题仍然存在于字节顺序......你显然在 python 端写大端,但如上所示,你会(很可能 - 它依赖于机器,但大端机器很少见这些天...) 阅读小端。为了在 C++ 端也独立于机器的字节顺序,您可以按如下方式修改代码:

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;

编辑:评论中的一些评论,因为这些评论已被移走:

好吧,实际上,已经有一个函数可以执行此操作:ntohl (thanks, WhozCraig,提示),因此您可以更轻松地完成它:

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

在讨论中发现的另一个问题,这次是在 python 方面:

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

encode 默认传递一个 utf-8 编码的字符串,在这种情况下这肯定不是我们想要的(200 将被转换为两个字节)。相反,我们需要使用本地机器的编码(在 windows 主机上,西欧很可能是 cp1252,中欧和东欧很可能是 cp1250)。