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

时间:2016-02-25 21:54:51

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

我使用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对象如下所示。

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

2 个答案:

答案 0 :(得分:1)

您事先清除缓冲区这一事实最终确定问题不在于boost :: asio,除非您建议它为某些未知目的保留内存。

或者:

  1. 发件人正在发送包含重复数据的数据报,或
  2. 问题出在缓冲区管理器类中,可能是字符串。

    我没有看到这堂课的重点。我建议你像其他人一样使用char数组重写代码。

答案 1 :(得分:1)

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

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));

以下是最小示例demonstrating 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写入ostream_iterator,而无需构建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.

这是一个完整的示例demonstrating使用write_hex函数将各种缓冲区类型的十六进制值打印到stdout,并使用自定义类型简化将十六进制写入ostream:< / p>

#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