繁体   English   中英

boost :: udp socket.recieve_from()将数据追加到缓冲区的末尾

[英]boost::udp socket.recieve_from() appends data to the end of the buffer

我已经使用boost_asio实现了一个udp_client。udp_client :: recieve_from()在下面给出。

void udp_client::recieve_from()
{
    for(unsigned int i = 0; i < m_buffer_manager.get_recieve_array().size(); ++i)
        m_buffer_manager.get_recieve_array()[i] = 0;

    /*Initialize our endpoint*/
    size_t len = m_socket.receive_from(
                     boost::asio::buffer(m_buffer_manager.get_recieve_array()), m_sender_endpoint);

    m_buffer_manager.message_buffer(m_buffer_manager.get_recieve_array(),len);
    std::cout << "Length of recieved message " << len << std::endl;
    /*dumps the message into std::cout for debugging.*/
    std::cout << m_buffer_manager.get_message_string() << std::endl;
    //std::cout.write((const char*)&m_buffer_manager.get_recieve_array()[0], len);

    packet_t ack_packet = { "ACK", {} };
    auto buffer = ack_packet.serialize();
    m_socket.send_to(boost::asio::buffer(buffer), m_endpoint);
}

udp_client.hpp文件如下所示。

class udp_client
{
public:
    udp_client(boost::asio::io_service& io_service,const std::string& host,const std::string& port);
    ~udp_client();
    void subscribe();
    void publish(const std::string& message);
    void recieve_from();

private:
    boost::asio::io_service& m_io_service;
    boost::asio::ip::udp::udp::socket m_socket;
    boost::asio::ip::udp::udp::endpoint m_endpoint;
    boost::asio::ip::udp::endpoint m_sender_endpoint;
    buffer_manager m_buffer_manager;
};

下面buffer_manager了用于管理接收缓冲区的buffer_manager对象。

class buffer_manager
{
public:
    typedef boost::array<unsigned char, 4096> m_array_type;
    buffer_manager();
    ~buffer_manager();
    void message_buffer(m_array_type &recv_buf,size_t size);
    buffer_manager::m_array_type & get_recieve_array();
    std::string & get_message_string();

private:
    std::string m_message;
    m_array_type m_recv_buf;
};

我的udp_client :: recieve_from()代码的问题是

size_t len = m_socket.receive_from(boost::asio::buffer(m_buffer_manager.get_recieve_array()), m_sender_endpoint);

收到一个数据包后返回1个数据包。 当它收到两个数据包时,它将收到整个两个数据包。 (即,第二个数据包的内容将附加到第一个数据包的内容。)

尽管有

for(unsigned int i = 0; i < m_buffer_manager.get_recieve_array().size(); ++i)
            m_buffer_manager.get_recieve_array()[i] = 0;

我在这里明确清除缓冲区。 这是什么原因呢? 我如何解决这个问题。

请在下面找到buffer_manager.cpp的实现。

#include <iostream>                                                                                                                                                                                                
#include <boost/array.hpp>
#include <boost/algorithm/hex.hpp>
#include <algorithm>
#include "buffer_manager.hpp"

buffer_manager::buffer_manager()
{

}
buffer_manager::~buffer_manager()
{

}
void buffer_manager::message_buffer(m_array_type &recv_buf,size_t size)
{
    auto it = recv_buf.begin();
    std::advance(it,size);
    boost::algorithm::hex(recv_buf.begin(), it, back_inserter(m_message));
}

buffer_manager::m_array_type& buffer_manager::get_recieve_array()
{
    return m_recv_buf;
}

std::string & buffer_manager::get_message_string()
{
    return m_message;
}

您事先清除缓冲区的事实最终提供了问题不在boost :: asio中,除非您建议它保留内存用于某些未知目的。

要么:

  1. 发送方正在发送具有重复数据的数据报,或者
  2. 问题出在缓冲区管理器类的某个地方,可能是字符串。

    我看不到这节课的重点。 我建议您像其他所有人一样使用char数组重写代码。

receive_from()操作正常运行,并且没有将数据附加到缓冲区的末尾。 另一方面, buffer_manager::message_buffer()使用back_insert_iterator且从不清除字符串,因此每次调用都会将其附加到m_message

void buffer_manager::message_buffer(...)
{
  auto it = recv_buf.begin();
  std::advance(it, size);
  boost::algorithm::hex(recv_buf.begin(), it, back_inserter(m_message));
                                           // ^~~ invokes m_message.push_back() for the
                                           //     range [recv_buf.begin(), it).
}

要解决此问题,请考虑事先清除字符串。

void buffer_manager::message_buffer(...)
{
  auto it = recv_buf.begin();
  std::advance(it, size);
  m_message.clear();
  boost::algorithm::hex(recv_buf.begin(), it, back_inserter(m_message));

这是一个演示 std::back_inserter的最小示例:

#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>

int main()
{
  std::string message = "abc";
  auto inserter = back_inserter(message);
  inserter = 'd';
  inserter = 'e';
  assert("abcde" == message);
}

我不清楚buffer_manager提供什么值。 但是,如果要打印缓冲区的十六进制值,请考虑使用ostream_iterator写入ostream ,而无需构造string的开销。 例如,以下实用程序函数将迭代器范围的十六进制值写入提供的ostream

template <typename Iterator>
void write_hex(Iterator first, Iterator last, std::ostream& out)
{
  boost::algorithm::hex(first, last, std::ostream_iterator<char>(out));
}

及其用法:

unsigned char data[3] = { 0, 10, 255 };
write_hex(std::begin(data), std::end(data), std::cout); // writes 000AFF to stdout.

这是一个完整的示例, 展示了使用write_hex函数将各种缓冲区类型的十六进制值打印到stdout,以及使用自定义类型简化了将十六进制写入ostream

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/hex.hpp>

// Utility funciton to write hex to a stream.
template <typename Iterator>
void write_hex(Iterator first, Iterator last, std::ostream& out)
{
  boost::algorithm::hex(first, last, std::ostream_iterator<char>(out));
}

namespace detail {

// Utility type to write an iterable as hex to a stream via the insertion
// operator.
template <typename Iterable>
struct hex_writer
{
  const Iterable& iterable;

  friend std::ostream& operator<<(std::ostream& stream, const hex_writer& object)
  {
    write_hex(std::begin(object.iterable), std::end(object.iterable), stream);
    return stream;
  }  
};

} // namespace detail

// Auxiliary function to create hex_writers.  Intended to be used for
// chaining writes to an ostream.
template <typename Iterable>
detail::hex_writer<Iterable> as_hex(const Iterable& iterable)
{
  return {iterable};
}

int main()
{
  // Using c-array.
  {
    unsigned char data[3] = { 0, 10, 255 };
    write_hex(std::begin(data), std::end(data), std::cout);
    std::cout << " " << as_hex(data) << std::endl;
  }

  // Using c++-array.
  {
    std::array<unsigned char, 3> data = {{ 0, 10, 255 }};
    write_hex(begin(data), end(data), std::cout);
    std::cout << " " << as_hex(data) << std::endl;
  }

  // Using vector.
  {
    std::vector<unsigned char> data = { 0, 10, 255 };
    write_hex(begin(data), end(data), std::cout);
    std::cout << " " << as_hex(data) << std::endl;
  }
}

输出:

000AFF 000AFF
000AFF 000AFF
000AFF 000AFF

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM