C++如何通过socket发送对象?

9
我是一名有用的助手,以下为您翻译的内容:

我有一个问题要问你。

我有这个类:

`

#define DIMBLOCK 128
#ifndef _BLOCCO_
#define _BLOCCO_

class blocco
{
    public:
        int ID;
        char* data;


        blocco(int id);
};

#endif




blocco::blocco(int id)
{
    ID = id;
    data = new char[DIMBLOCK];
}

这个应用程序有客户端和服务器。 在我的服务器主函数中,我通过以下方式实例化了一个类的对象: blocco a(1);

之后,我使用套接字打开客户端和服务器之间的连接。 问题是:我该如何将此对象从服务器发送到客户端或反之亦然? 请帮我解决这个问题。


很可能需要Socket代码。即使如此,除非您设置了复杂的RPC系统,否则最多只能获得一份副本(这可能是您所需的全部)。 - WhozCraig
3个回答

16

在字面意义上,无法通过TCP连接发送对象。套接字只知道如何传输和接收一系列字节。因此,您可以通过TCP连接发送一系列字节,以特定的格式进行格式化,以便接收程序知道如何解释它们并创建与发送程序要发送的对象相同的对象。

该过程称为序列化(以及在接收端的反序列化)。序列化不是内置于C ++语言本身中的,因此您需要一些代码来完成它。它可以手动完成,也可以使用XML,或通过Google的协议缓冲区,或将对象转换为人类可读的文本并发送该文本,或任何其他方式。

请查看这里获取更多信息。


那么,不可能像这样做:ret = send(sock, reinterpret_cast<void*>(&a), sizeof(blocco),0)吗? - rosekarma
1
不行。这样做有很多原因...首先,它不能跟随指针(例如,通过这种方式发送的blocco的接收者将接收到(data)指针的值,而不是(data)指向的字符,这是没有用的)。它还不能正确处理填充和字节序问题。 - Jeremy Friesner
@rosekarma那有什么用呢?如果你连发送的字节数据都不知道,你怎么写代码接收数据呢?为了编写接收数据的代码,首先要知道编码ID所需的字节数。但是你甚至连这个都不知道--更糟糕的是,如果你更改编译器、平台等等,这个值将会改变。 - David Schwartz

3
你可以使用序列化来完成这个操作。这意味着将对象分解为若干部分,以便于在套接字上发送这些元素。然后您需要在连接的另一端重建类。在Qt中,提供了QDataStream类,可提供此功能。结合QByteArray,可以创建一个数据包进行发送。思路很简单:
发送者:
QByteArray buffer;
QDataStream out(&buffer);
out << someData << someMoreData;

收件人:

QByteArray buffer;
QDataStream in(&buffer);
in >> someData >> someMoreData;

现在您可能想提供额外的构造函数:
class blocco
{
    public:
        blocco(QDataStream& in){
            // construct from QDataStream
        }

        //or
        blocco(int id, char* data){
            //from data
        }
        int ID;
        char* data;


        blocco(int id);
};

扩展示例


0

我不知道我会因此受到多少指责,但是我尝试了这个方法并认为应该分享一下。我是socket编程的初学者,所以请别生气。

我的做法是创建一个字符数组,其大小与表示服务器端存储块的类相同。然后我在客户端使用recv接收了存储块,并将该存储块强制转换为对象,就这样!我成功地将对象从客户端发送到服务器。

示例代码:

blocco *data;
char blockOfData[sizeof(*data)];

if(recv(serverSocket, blockOfData, sizeof(*data), 0) == -1) {
    cerr << "Error while receiving!!" << endl;
    return 1;
}

data = (blocco *)blockOfData;

现在,您可以使用此作为指向对象的指针对此数据执行任何操作。只需记住不要尝试删除/释放此指针,因为该内存分配给了堆栈上的数组blockOfData。

希望这可以帮助您实现类似的功能。

附注:如果您认为我所做的编码方式很差,请告诉我原因。如果这确实是一个不好的想法,我不知道为什么。谢谢!


如果你想知道为什么这种方法行不通,尝试在recv()返回后打印'received'块对象的'data'成员项所指向的字符字符串。你会发现该字符串未被传输,你要么打印垃圾数据,要么(更有可能)程序将在尝试取消引用'data'指针时崩溃,因为它被设置为指向发送方内存空间中有效地址,在接收方内存空间中无效。 - Jeremy Friesner
我在我的MacBook上实现了这个,并在同一台机器上运行了客户端和服务器。我成功地能够访问数据,没有遇到任何崩溃/垃圾值问题。也许如果我尝试在具有不同字节序的多个系统之间进行此操作,我会遇到问题? - Siddharth Gupta
我现在明白了你的意思,如果我有指针,我将面临这些问题。虽然如果我有一个字符串(就像我代码中的那样),那么我就不会遇到这些问题。 - Siddharth Gupta
大多数字符串类内部都包含指针,因此您可能仍然会遇到这个问题。即使您没有,您仍将面临其他问题(字节序差异、字长差异、结构填充差异),除非在特定情况下(即除非发送和接收程序都是使用相同的CPU架构和相同的操作系统,使用相同设置的编译器编译)。 - Jeremy Friesner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接