boost :: asio和标准C套接字接口之间的合作

时间:2011-06-14 22:20:14

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

我目前正在开发一个小项目:有一个协议,用于通过使用标准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不会将网络转换为主机(little-endian)byteorder
  2. 我误解了如何使用boost :: asio :: streambuf with streams
  3. 旧C接口和boost之间存在一些不兼容性(但我不这么认为 因为我发现boost函数只是它的包装器。)
  4. 编辑: 嗯,他们说“不要赞美福特直到你过去”。现在我在我的代码的另一个地方有一个非常类似的问题。我有一个以下结构,作为上面提到的请求的回复发送:

    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开头,一个如果成功,另一个如果失败。现在,我根本不知道如何以其他方式做到这一点。

2 个答案:

答案 0 :(得分:3)

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

请注意,如果您在每次提取后检查流状态,这将立即显而易见,因为总是应该使用非丢弃代码。

答案 1 :(得分:0)

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

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

您可以使用属性(请参阅the GCC manual

来解决这个问题,例如在GCC中
struct __attribute__ ((__packed__)) request { ...

是的,我确实错过了你试图阅读文本而不是二进制的事实。首先修复,稍后通过对齐/填充进行咬合:)