[英]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. 我有一个简单的cpp服务器,它从python客户端接收一个char *缓冲区,并将其解包以使用数据。 the python client sends a buffer which includes 2 "different" data types - string and int.
python客户端发送一个包含2种“不同”数据类型的缓冲区-字符串和整数。 the buffer should look like this -
缓冲区应如下所示-
which means if the client wants to send the message code 200, and the data "ok", he would have to send the buffer [2002ok]. 这意味着如果客户端要发送消息代码200,并且数据“确定”,则他必须发送缓冲区[2002ok]。 But I have decided that the client would send the buffer as chars.
但是我已经决定客户端将缓冲区作为char发送。
so, the buffer would look like this- [Èok] 因此,缓冲区看起来像这样-[È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..) (È= 200的ascii值,= 2的ascii值)(编辑:我不知道为什么,但是这里无法显示ASCII值2。)
The problem is, That when I unpack the 3 parts of the buffer, they are somehow distorted. 问题是,当我打开缓冲区的3个部分的包装时,它们会以某种方式扭曲。
here is my client side (Python): 这是我的客户端(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): 这是我的服务器端(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
消息代码是200
is actually 实际上是
The message code is ├
消息代码为├
Where is my mistake? 我的错误在哪里? Thanks, M.
谢谢,M
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;
}
ie 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. 问题仍然是字节序...您显然在python端编写了大字节序,但是如上所示,您(很可能–它是依赖于机器的,但是这些天大字节序的机器变得非常稀少了...)读取小字节序。 To get independent of machine's byte order on C++ side, too, you could modify the code as follows:
为了也独立于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;
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: 好吧,实际上,已经有一个函数正在执行此操作:
ntohl
(感谢, WhozCraig给出了提示),因此您可以轻松得多:
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: 在讨论中发现的另一个问题,这次是在python方面:
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). encode
默认情况下,提供了一个utf-8
编码过的字符串,这当然不是我们想要在这种情况下,(200将被转换为两个字节)。 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). 相反,我们需要使用本地计算机的编码(在Windows主机上,西欧很可能是cp1252,中欧和东欧很可能是cp1250)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.