您好我有一个客户端程序和一个服务器程序。 我创建了一个这样的结构
struct player
{
Int x,y;
Int score;
Std::string name;
}
我用:
创建了对象player p;
我初步确定了它:
p.x = 100; p.y = 200; p.score = 281;
p.name = "DiCri";
我将对象发送到服务器。
SDLNet_TCP_Send(client, (char*)&p, sizeof(p));
一切正常。 服务器获取带有数据的对象。 唯一的问题是名称。 服务器说x是100,y是200,得分是281,名字是一种奇怪的随机符号。 我不知道为什么。 救命。如何解决? 如果那是char *而不是字符串,也会发生这种情况。
由于
EDIT1: 我发现了一个类似于我的问题:一个对象的序列化。 提出此问题的用户也希望通过网络发送此对象。 我会尝试按照答案
EDIT2: 使用char name [100]它可以工作。
EDIT3: 谢谢,现在一切正常!抱歉英语不好,因为我是意大利人!
答案 0 :(得分:1)
Player
包含3个int
和std::string
这个int
可以很容易地写入write
(watch out for the differing byte orders, endian, used by processors)的流,但string
太复杂了。选项1是用固定大小的string
数组替换char
以简化结构,但这会增加更多的痛苦。 char
数组很容易溢出,无论你是否使用它,总是会写出数组的完整大小。
更好的方法是建立通信协议并序列化数据。
首先建立协议使用的字节序,以便双方确切地知道使用哪个字节顺序。传统上Big Endian用于网络通信,但是大端设备越来越少,因此越来越多地成为“你的电话”。
让我们坚持使用big endian,因为它的工具是古老的,众所周知的,并且已经很成熟。如果您使用套接字库,则赔率非常高,您可以访问tools to perform the operations required。
接下来,显式调整整数数据类型的大小。 C ++的不同实现可能有different sizes for fundamental types。这个解决方案很简单:不要使用基本类型。相反,请使用cstdint
现在我们的结构看起来像
struct player
{
int x,y;
int score;
std::string name;
}
它需要看起来更像
struct player
{
int32_t x,y;
int32_t score;
std::string name;
}
现在没有关于整数大小的惊喜。代码要么编译要么不支持int32_t
。不要笑了。那里还有8位微控制器。
现在我们知道了整数的样子,我们可以创建一对函数来处理读写:
bool sendInt32(int32_t val)
{
int32_t temp = htonl(val);
int result = SDLNet_TCP_Send(client, (char*)&temp, sizeof(temp));
return result == sizeof(temp); // this is simplified. Could do a lot more here
}
bool readInt32(int32_t & val)
{
int32_t temp;
if (readuntil(client, (char*)&temp, sizeof(temp)))
{
val = ntohl(temp);
return true;
}
return false;
}
其中readuntil
是一个函数,它一直从套接字读取数据,直到套接字失败或读取了所有请求的数据。不要假设您想要的所有数据都将在同一时间到达。有时你必须等待。即使你把它全部写在一个块中,它也不一定会在一个块中到达。处理这个问题是另一个问题,但它每周都要问一次,所以你应该能够通过一些搜索找到一个好的答案。
现在为string
。你去C路线并发送一个空终止的字符串,但我发现这使得读者比它需要的复杂得多。相反,我在字符串数据前加上长度,所以读者所要做的就是读取长度,然后读取长度字节。
基本上这个:
bool sendstring(const std::string & str)
{
if (sendInt32(str.size()))
{
int result = SDLNet_TCP_Send(client, str.c_str(), str.size());
return result == str.size();
}
return false;
}
bool readstring(std::string & str)
{
int32 len;
if (readInt32(len))
{
str.resize(len);
return readuntil(client, str.data(), len) == len;
}
return false;
}
总之,作家看起来像
bool writePlayer(const Player & p)
{
return sendInt32(p.x) &&
sendInt32(p.y) &&
sendInt32(p.score) &&
sendString(p.name);
}
和读者
bool readPlayer(Player & p)
{
return readInt32(p.x) &&
readInt32(p.y) &&
readInt32(p.score) &&
readString(p.name);
}
答案 1 :(得分:-1)
首先,Std :: string应该被char数组替换。 您还了解Int在不同操作系统上的网络代表。必须使用htons()和ntohs通过网络发送16位整数。