将对象发送到服务器

时间:2017-06-30 20:24:23

标签: c++ networking network-programming social-networking

您好我有一个客户端程序和一个服务器程序。 我创建了一个这样的结构

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: 谢谢,现在一切正常!抱歉英语不好,因为我是意大利人!

2 个答案:

答案 0 :(得分:1)

Player包含3个intstd::string这个int可以很容易地写入writewatch 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

中定义的fixed width integers

现在我们的结构看起来像

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位整数。