【问题标题】:sending struct through socket; server and client on same machine通过套接字发送结构;服务器和客户端在同一台机器上
【发布时间】:2010-08-31 12:03:34
【问题描述】:

我的服务器和客户端在同一台机器上运行,所以我没有字节序问题等。我需要一些适用于 vc++ 和 g++ 的东西,并且可能是最简单的方法。我可以用什么发送结构?

编辑

struct Info
{
     int**   fields; 
     char**  field_names;
};

【问题讨论】:

  • 这个结构是什么样的?是 POD 吗?
  • 吊舱?该结构有一个 int** 和一个 char**
  • 请将完整的结构添加到问题中。它将帮助我们回答它。
  • 我的结构如下 struct Info{ int **fields;字符 **field_names; };
  • 字段和字段名称是否为 NULL 终止?

标签: c++ visual-c++


【解决方案1】:

看看Boost.Serialization,这是我在another question发布的一个相当简单的例子

#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/string.hpp>

#include <string>

struct Message
{
    std::string _a;
    std::string _b;

    template <class Archive>
    void serialize(
            Archive& ar,
            unsigned int version
            )
    {
        ar & _a;
        ar & _b;
    }
};

int
main()
{
    Message msg;
    msg._a = "hello";
    msg._b = "world";
    std::ostringstream os;
    boost::archive::text_oarchive ar( os );
    ar & msg;
}

请注意,序列化库的功能远不止于此。它可以序列化指针、引用、容器和其他 Boost 库中的许多对象。我这里的例子展示了侵入式序列化,如果你不能修改你的结构,也有办法序列化non-intrusively

【讨论】:

  • 我的结构如下 struct Info{ int **fields;字符 **field_names; };提升不是矫枉过正吗?
  • 如果您已经在使用 boost,那么使用 Boost.Serialization 很可能并不过分。仅仅为了这个目的使用它可能是矫枉过正,这取决于你。
  • 是的..我需要一些东西来进行序列化。
【解决方案2】:

你可以像这样声明一个静态无符号字符:

#define MSGBUFSIZE  512
static unsigned char ClientSendBuf[MSGBUFSIZE];

然后像这样将你的结构复制到数组中:

memmove(&ClientSendBuf[2], &struct, sizeof(struct));

现在这是下一个特定于实现的地方。我正在使用 Borland C++,所以我的发送行为如下:

ClientSocket->Socket->SendBuf(ClientSendBuf, ClientSendBuf[0]+CRC16SIZE);

我使用 ClientSendBuf[0] 的原因是因为我的消息大小存储在 ClientSendBuf[0] 中,如下所示:

ClientSendBuf[0] = 4 + sizeof(struct);             //Byte Count

(注意:将 struct 替换为您的 struct 的名称)

我还在消息末尾添加了一个 CRC 检查,如下所示:

#define CRC16SIZE   2

...

cs = CheckSum((unsigned char *)ClientSendBuf, ClientSendBuf[0]);
    memmove(&ClientSendBuf[ClientSendBuf[0]], &cs, CRC16SIZE);

...

unsigned short __fastcall TFormMenu::CheckSum(unsigned char *p, int length)
{
    int i;

    for (cs = 0, i = 0; i < length; i++) {
        cs += p[i];
    }
    return cs;
}

基本上,所有这些简单的 CRC 校验所做的都是对所有字节求和,以确定发送的字节数是否正确。如果数据被破坏(顺便说一句,这在有问题的 WiFi 连接中很常见),那么服务器应该抛出一个 CRC 错误。

这一切都假设你有一个 POD 结构。 static 部分不是必需的,但我在特定应用程序中是如何做到的。我还掩盖了一些细节。如果您有任何问题,请在 cmets 中发帖。 YMMV。

【讨论】:

    【解决方案3】:

    您需要确保在 VC++ 和 G++ 中使用的数据成员具有相同的字节大小和对齐方式。

    如果您有一个可变长度的数据成员,通过套接字传输它的最佳方法是也发送大小。

    假设你有这样的结构:

    struct DataStruct
    {
       int x;
       char* message;
       short messageLen;
    }
    

    您可以通过套接字发送数据,每个成员的成员,以指定的格式,因为您知道非预定义大小成员的大小。

    在 G++ 和 VC++ 中,整数都是 4 个字节;字符都是1个字节;短裤是 2 个字节。

    首先传输 x 值,然后是 messageLen 变量,并使用此变量在另一侧创建变量缓冲区大小。然后您可以将消息数据写入 char*。

    【讨论】:

      【解决方案4】:

      您拥有的结构具有指向数据的指针,而不是指向数据本身的指针。如果您要在结构中使用 POD 类型(即 int 和 char[]),那么它可以直接在套接字上发送。

      由于结构内的对齐/填充,可能会传输额外的字节,但如果您对此表示满意,那么您就可以开始了。这是因为您在同一个操作系统上运行客户端和服务器。如果涉及到不同的操作系统,对齐/填充会造成问题。

      boost::asio 有一些非常简单的示例供您使用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-21
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 2020-07-10
        • 1970-01-01
        • 2014-10-05
        • 2017-06-01
        相关资源
        最近更新 更多