使用Boost Asio传输UDP数据包的低速(带宽)

时间:2017-07-10 05:39:26

标签: performance asynchronous boost bandwidth asio

以下是我使用boost asio编写的异步UDP客户端和服务器的示例,用于测试asio性能(速度)。 Server是一个简单的程序,用于回显从客户端收到的消息,如下所示:

异步UDP服务器:

#include <iostream>
#include <string>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>

using boost::asio::ip::udp;


class udp_server
{
public:
udp_server(boost::asio::io_service& io_service) : socket_(io_service, udp::endpoint(udp::v4(), 4000))
{
    start_receive();
}

private:
void start_receive()
{
    socket_.async_receive_from(
        boost::asio::buffer(recv_buffer_), remote_endpoint_,
        boost::bind(&udp_server::handle_receive, this,
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred));
}

void handle_receive(const boost::system::error_code& error,std::size_t bytes_transferred)
{

    if (!error || error == boost::asio::error::message_size)
    {
        std::string copy(recv_buffer_, bytes_transferred);
        boost::shared_ptr<std::string> message( new std::string(recv_buffer_, bytes_transferred) );

        socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
        boost::bind(&udp_server::handle_send, this, message,
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred));

        start_receive();
    }
}

void handle_send(boost::shared_ptr<std::string> /*message*/,
    const boost::system::error_code& /*error*/,
    std::size_t /*bytes_transferred*/)
{
}

udp::socket socket_;
udp::endpoint remote_endpoint_;
char recv_buffer_[300];
};

int main()
{
    try
    {
        boost::asio::io_service io_service;
        udp_server server(io_service);
        io_service.run();
    }
    catch (std::exception& e)
    {
    std::cerr << e.what() << std::endl;
    }

    return 0;
}

客户端只是以异步模式为服务器发送消息并等待回复并从服务器接收回送支持的消息。我使用chrono来计算发送和接收消息所用的时间。

客户端代码如下:

#ifdef WIN32
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#endif

#include <fstream>
#include <iostream>
#include <stdlib.h>
#include <chrono>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

using namespace boost::asio;
io_service service;
auto ts = std::chrono::high_resolution_clock::now();

#define MEM_FN(x)       boost::bind(&self_type::x, shared_from_this())
#define MEM_FN1(x,y)    boost::bind(&self_type::x, shared_from_this(),y)
#define MEM_FN2(x,y,z)  boost::bind(&self_type::x, shared_from_this(),y,z)

class talk_to_svr : public boost::enable_shared_from_this<talk_to_svr>, boost::noncopyable {
    typedef talk_to_svr self_type;
    talk_to_svr(const std::string & message, ip::udp::endpoint ep) 
      : sock_(service), started_(true), message_(message), ep_(ep) {}
    void start(ip::udp::endpoint ep) {
        this->t00 = std::chrono::high_resolution_clock::now();
        sock_.async_connect(ep, MEM_FN1(on_connect,_1));
    }
public:
    typedef boost::system::error_code error_code;
    typedef boost::shared_ptr<talk_to_svr> ptr;

    static ptr start(ip::udp::endpoint ep, const std::string & message) {
        ptr new_(new talk_to_svr(message, ep));
        new_->start(ep);
        return new_;
    }
    void stop() {
        if ( !started_) return;
        started_ = false;
        sock_.shutdown(boost::asio::ip::udp::socket::shutdown_both);
        sock_.close();
        service.stop();
        std::cout << "Sucket successfully shutdowned and closed" << std::endl;
    }
    bool started() { return started_; }
private:
    void on_connect(const error_code & err) {
    this->t0 = std::chrono::high_resolution_clock::now();
        if ( !err)      {
            std::cout << "Successfully Connected" << std::endl;
            do_write(message_);

        }
        else            stop();
    }
    void on_read(const error_code & err, size_t bytes) {
        if ( !err) {
        this->t1 = std::chrono::high_resolution_clock::now();
            std::cout << "Client successfully read " << bytes << " bytes of data as "; //<< std::endl;
            std::string copy(read_buffer_, bytes);
            std::cout << copy << std::endl;
            std::cout.precision(6);
            auto Tc = 1.e-9*std::chrono::duration_cast<std::chrono::nanoseconds>(this->t00-ts).count();
            auto Ts = 1.e-9*std::chrono::duration_cast<std::chrono::nanoseconds>(this->t0-ts).count();
            auto Te = 1.e-9*std::chrono::duration_cast<std::chrono::nanoseconds>(this->t1-ts).count();
            std::cout << "Start to connect @time: " << Tc << " seconds" << std::endl;
            std::cout << "Start to send message @time: " << Ts << " second(s)" << std::endl;
            std::cout << "Recived messages @time: " << Te << " second(s)" << std::endl;
            auto dt_du = 1.e-9*std::chrono::duration_cast<std::chrono::nanoseconds>(this->t1-this->t0).count();
            std::cout << "It tooks " << dt_du << " second(s) to send and recieve " << bytes << " bytes of data" << std::endl;
        }
        else {
            std::cout << "Error occured in reading data from server" << std::endl;
        }
    }

    void on_write(const error_code & err, size_t bytes) {
        std::cout << "Client successfully sent " << bytes << " bytes of data" << std::endl;
        do_read();
    }

    void do_read() {

        sock_.async_receive_from(buffer(read_buffer_),
                   ep_,
                   MEM_FN2(on_read,_1,_2));

    }
    void do_write(const std::string & msg) {
        if ( !started() ) return;
        std::copy(msg.begin(), msg.end(), write_buffer_);
        sock_.async_send_to( buffer(write_buffer_, msg.size()), 
                                ep_, MEM_FN2(on_write,_1,_2));
    }

public:
    std::chrono::time_point<std::chrono::high_resolution_clock> t00;
    std::chrono::time_point<std::chrono::high_resolution_clock> t0;
    std::chrono::time_point<std::chrono::high_resolution_clock> t1;

private:
    ip::udp::socket sock_;
    ip::udp::endpoint ep_;
    enum { max_msg = 40 };
    char read_buffer_[max_msg];
    char write_buffer_[max_msg];
    bool started_;
    std::string message_;
};

int main(int argc, char* argv[]) {

    int port = atoi(argv[2]);
    std::string ipp = std::string(argv[1]);
    std::cout << "Server ip: " << argv[1] << std::endl;
    std::cout << "Server port: " << (port) << std::endl;
    ip::udp::endpoint ep( ip::address::from_string(ipp), port);
    ts = std::chrono::high_resolution_clock::now();
    talk_to_svr::start(ep, "Message");

    service.run();
}

编译并执行服务器:

c++ echo_server.cpp -std=c++11 -o echo_client -I /path/to/boost_1_57_0/ -l pthread -l boost_system -l boost_thread

./echo_server

编译并执行客户端:

c++ echo_client.cpp -std=c++11 -o echo_client -I /path/to/boost_1_57_0/ -l pthread -l boost_system -l boost_thread

./echo_client 127.0.0.1 4000

在同一台机器(本地主机)上运行服务器和客户端时,我想知道为什么boost asio具有如此差的性能,因为它需要80微秒(平均)发送和接收36个字节(28个字节用于头+ 8个数据字节)相当于 3.4 Mbits / sec !!!!

有没有办法增加UDP套接字性能或任何其他技巧来优化代码?

0 个答案:

没有答案