【问题标题】:C++ How can I send an object via socket?C++ 如何通过套接字发送对象?
【发布时间】:2013-09-02 05:40:24
【问题描述】:

我有一个问题要问你。

我有这门课:

`

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

`

并且应用程序有一个客户端和一个服务器。 在我的服务器的主体中,我以这种方式实例化了这个类的一个对象: 块 a(1);

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

【问题讨论】:

  • 可能需要套接字代码。即便如此,除非您正在设置一个复杂的 RPC 系统,否则您将获得的最好的结果是一个 副本(这可能是您所需要的全部)。

标签: c++ sockets tcp send recv


【解决方案1】:

从字面意义上来说,通过 TCP 连接发送对象是不可能的。套接字只知道如何传输和接收字节流。所以你可以做的是通过 TCP 连接发送一系列字节,以这样一种方式格式化,即接收程序知道如何解释它们并创建一个与发送程序想要发送的对象相同的对象。

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

查看here 了解更多信息。

【讨论】:

  • 所以,不可能这样做:ret = send(sock, reinterpret_cast(&a), sizeof(blocco),0);?
  • 没有。由于多种原因,这将不起作用......其中一个原因是,它不会跟随指针(例如,以这种方式发送的 blocco 的接收者将接收(数据)指针的值而不是 ( data) 指向,这没有用)。它也不能正确处理填充和字节序问题。
  • @rosekarma 这有什么好处?鉴于您实际上不知道您发送了哪些字节,您将如何编写代码来接收数据。要编写代码来接收数据,您首先需要知道有多少字节对 ID 进行编码。但你甚至不知道——更糟糕的是,如果你改变编译器、平台等,它就会改变。
【解决方案2】:

您可以使用serialization 执行此操作。这意味着将对象拉成碎片,以便您可以通过套接字发送这些元素。然后你需要在连接的另一端重建你的类。在 Qt 中有 QDataStream class 提供这样的功能。结合 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);
};

extended example

【讨论】:

    【解决方案3】:

    我不知道我会为此受到多少抨击,但我试过了,尽管我应该分享它。我是套接字编程的初学者,所以不要生气。

    我所做的是创建了一个字符数组,该数组的大小与类一样大(代表服务器端的内存块)。然后我在客户端recved 内存块并将该内存块类型转换为对象,瞧!我设法将一个对象从客户端发送到服务器。

    示例代码:

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

    现在您可以使用 this 作为指向对象的指针对这些数据做任何您想做的事情。请记住不要尝试删除/释放此指针,因为此内存已分配给堆栈上的数组 blockOfData。

    如果你想实现这样的东西,希望这会有所帮助。

    PS:如果您认为我所做的编码方式不佳,请告诉我原因。我不知道为什么这是一个坏主意(如果这样做实际上是个坏主意)。谢谢!!

    【讨论】:

    • 如果你想知道为什么这种方法不起作用,尝试在recv()返回后打印出'received' blocco对象的'data'成员项所指向的字符串。你会发现字符串没有被传输,你要么打印出垃圾,要么(更有可能)你的程序在尝试取消引用数据指针时崩溃,该指针设置为指向一个有效的地址发送者的内存空间,但不在接收者的内存空间中。
    • 我在我的 macbook 上实现了这个,并在同一台机器上运行客户端和服务器。我成功地访问了数据,并且没有遇到任何崩溃/垃圾值问题。也许如果我尝试在具有不同字节序系统的多个系统上执行此操作,我会遇到问题?
    • 我现在明白你的意思了,如果我有指点,我会面对这些问题。虽然如果我有一个字符串(我在我的代码中做了),那么我就不会遇到这些问题。
    • 大多数字符串类在内部都包含一个指针,因此您可能仍然会遇到这个问题。但是,即使您没有这样做,您仍然会面临其他问题(字节序差异、字长差异、结构填充差异),除非在特定情况下(即,除非发送和接收程序都被编译)对于相同的 CPU 架构和相同的操作系统,使用相同的编译器和相同的设置)
    猜你喜欢
    • 2012-03-13
    • 1970-01-01
    • 2019-04-21
    • 2014-01-11
    • 2022-01-15
    • 2021-01-11
    • 2014-03-24
    相关资源
    最近更新 更多