【问题标题】:Cooperation between boost::asio and standard C socket interfaceboost::asio与标准C socket接口的配合
【发布时间】:2011-09-15 02:27:36
【问题描述】:

我目前正在做一个小项目:有一个协议可以通过标准 C 接口实现的 UDP 发送一些字符串。

虽然它工作得很好,但我想用一些更复杂的 C++ 重写它(考虑它的练习)。

目前是这样的:客户想要该字符串,因此它发送以下struct

struct request {
  uint8_t msg_type;// == 1
  uint64_t key; // generated randomly to identify each request
}

在新的实现中,我想使用boost::asio,所以在服务器中我有以下代码:

boost::asio::io_service io_service;
boost::asio::ip::udp::endpoint client_endpoint;
boost::asio::ip::udp::socket socket(io_service,
        boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(),
        m_serverPort));
boost::asio::streambuf sb;
boost::asio::streambuf::mutable_buffers_type mutableBuf =
        sb.prepare(sizeof(request));
size_t received_bytes = socket.receive_from(mutableBuf, client_endpoint);
sb.commit(received_bytes);

request r;
std::istream is(&sb);
is >> msg_type;
is >> key;
key = __bswap64(key); // I'm using network byteorder for numbers sent with this protocol
                      // and there's no ntohll function on Snow Leopard (at least I can't
                      // find one)
sb.consume(received_bytes);

这是我的问题:我尝试以这种方式接收的“关键”值是错误的 - 我的意思是我得到了我没有发送的东西。

以下是我的怀疑:

  1. __bswap64 不会将网络转换为主机(小端)字节序
  2. 我误解了如何将 boost::asio::streambuf 与流一起使用
  3. 旧的 C 接口和 boost 之间存在一些不兼容(但我不这么认为 因为我发现 boost 函数只是它的包装器)

编辑: 嗯,他们说“在你克服之前不要赞美福特”。现在我的代码的另一个地方有一个非常相似的问题。我有一个以下结构,它作为对上面提到的请求的回复发送:

struct __attribute__ ((packed)) CITE_MSG_T
{
        uint8_t msg_id;
        uint64_t key; // must be the same as in request
        uint16_t index; // part number
        uint16_t parts; // number of all parts
    CITE_PART_T text; // message being sent
};

//where CITE_PART_T is:
struct __attribute__ ((packed)) CITE_PART_T
{ 
        uint16_t data_length;
        char* data;
};

以及以下代码:http://pastebin.com/eTzq6AWQ。 不幸的是,其中还有另一个错误,我又读到了一些我没有发送的东西——replyMsg.parts 和 replyMsg.index 总是 0,尽管旧的实现说它们是例如 3 和 10。这次出了什么问题?如您所见,我负责填充,我使用 read 而不是 operator>>。如果您想知道为什么我逐个字段地阅读该结构,这里有一个答案:服务器发送两个不同的结构,都以 msg_id 开头,一个表示成功,另一个表示失败。现在,我根本不知道该怎么做。

【问题讨论】:

    标签: c++ sockets boost stream boost-asio


    【解决方案1】:

    你忘记了填充。您的请求结构可能在第一个和第二个成员之间由编译器插入至少三个字节,如下所示:

    struct request {
        uint8_t msg_type;
        char __pad__[3]; // or 7 on 64-bit machine.
        uint64_t key;
    };
    

    你可以解决这个问题,比如在 GCC 中,使用属性(参见 the GCC manual):

    struct __attribute__ ((__packed__)) request { ...
    

    是的,我确实错过了您尝试读取文本而不是二进制的事实。先解决这个问题,稍后会被对齐/填充咬住:)

    【讨论】:

    • 好的,好的 - 我实际上已经解决了填充问题,但在我的代码深处,所以我记得写它比搜索它要快实际声明。真正的问题是我使用 operator>> 而不是 read。无论如何感谢您的帮助!
    【解决方案2】:

    您正在使用格式化输入,就像发送的数据是文本一样——您需要un格式化输入。阅读 std::istream::read 成员函数,因为它是您应该使用的,而不是 operator>>

    请注意,如果您在每次提取后检查流状态,这将立即显而易见,因为在非一次性代码中始终应该这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-08
      • 1970-01-01
      • 2017-04-27
      • 2012-05-25
      • 2016-05-11
      • 1970-01-01
      • 2011-08-09
      • 1970-01-01
      相关资源
      最近更新 更多