Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通过boost::asio/io完成端口间歇性无数据传输 问题_C++_Windows_Performance_Boost Asio_Io Completion Ports - Fatal编程技术网

C++ 通过boost::asio/io完成端口间歇性无数据传输 问题

C++ 通过boost::asio/io完成端口间歇性无数据传输 问题,c++,windows,performance,boost-asio,io-completion-ports,C++,Windows,Performance,Boost Asio,Io Completion Ports,我使用的是一个项目,其中同一台机器上的两个进程使用TCP/IP进行通信。其中一个生成数据供另一个读取,但我遇到了一个问题,即间歇性地没有数据通过连接发送。我把它归结为下面一个非常简单的例子,基于 这些过程(下面的源代码)一开始就很好,以快速的速率将数据从发送方传递到接收方。然后突然之间,在大约5秒钟的时间里,根本没有数据传输。然后,数据会再次传递,直到下一次莫名其妙的暂停。在这五秒钟内,进程占用了0%的CPU,其他进程似乎没有做任何特别的事情。暂停的时间总是相同的——5秒 我正试图找出如何摆脱这

我使用的是一个项目,其中同一台机器上的两个进程使用TCP/IP进行通信。其中一个生成数据供另一个读取,但我遇到了一个问题,即间歇性地没有数据通过连接发送。我把它归结为下面一个非常简单的例子,基于

这些过程(下面的源代码)一开始就很好,以快速的速率将数据从发送方传递到接收方。然后突然之间,在大约5秒钟的时间里,根本没有数据传输。然后,数据会再次传递,直到下一次莫名其妙的暂停。在这五秒钟内,进程占用了0%的CPU,其他进程似乎没有做任何特别的事情。暂停的时间总是相同的——5秒

我正试图找出如何摆脱这些摊位,以及是什么原因造成了这些摊位

整个运行期间的CPU使用率:

注意,在运行过程中,CPU的使用量有三次下降,“run”是服务器进程和客户端进程的单个调用。在这些下跌期间,没有提供任何数据。每次运行时的下陷次数和时间不同——有时根本没有下陷,有时多次下陷

我可以通过改变读取缓冲区的大小来影响这些暂停的“概率”——例如,如果我将读取缓冲区设置为发送块大小的倍数,那么这个问题似乎几乎消失了,但不是完全消失

来源和测试描述 我使用VisualStudio2005,使用Boost1.43和Boost1.45编译了以下代码。我在Windows Vista 64位(四核)和Windows 7 64位(四核和双核)上进行了测试

服务器接受连接,然后简单地读取和丢弃数据。无论何时执行读取,都会发出新的读取

客户端连接到服务器,然后将一组数据包放入发送队列。在此之后,它一次写入一个数据包。每当写入完成时,就写入队列中的下一个数据包。一个单独的线程监视队列大小,并每秒将其打印到stdout。在io暂停期间,队列大小保持完全相同

我曾尝试使用分散io(在一个系统调用中写入多个数据包),但结果是一样的。如果我在Boost中使用
Boost\u ASIO\u disable\u IOCP
禁用IO完成端口,问题似乎会消失,但代价是吞吐量显著降低

// Example is adapted from async_tcp_echo_server.cpp which is
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Start program with -s to start as the server
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif                      

#include <iostream>
#include <tchar.h>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

#define PORT "1234"
using namespace boost::asio::ip;
using namespace boost::system;

class session {
public:
    session(boost::asio::io_service& io_service) : socket_(io_service) {}

    void do_read() {
        socket_.async_read_some(boost::asio::buffer(data_, max_length),
            boost::bind(&session::handle_read, this, _1, _2));
    }

    boost::asio::ip::tcp::socket& socket() { return socket_; }
protected:
    void handle_read(const error_code& ec, size_t bytes_transferred) {
        if (!ec) {
            do_read();
        } else {
            delete this;
        }
    }

private:
    tcp::socket socket_;
    enum { max_length = 1024 };
    char data_[max_length];
};

class server {
public:
    explicit server(boost::asio::io_service& io_service)
        : io_service_(io_service)
        , acceptor_(io_service, tcp::endpoint(tcp::v4(), atoi(PORT)))
    {
        session* new_session = new session(io_service_);
        acceptor_.async_accept(new_session->socket(),
            boost::bind(&server::handle_accept, this, new_session, _1));
    }

    void handle_accept(session* new_session, const error_code& ec) {
        if (!ec) {
            new_session->do_read();
            new_session = new session(io_service_);
            acceptor_.async_accept(new_session->socket(),
                boost::bind(&server::handle_accept, this, new_session, _1));
        } else {
            delete new_session;
        }
    }

private:
    boost::asio::io_service& io_service_;
    boost::asio::ip::tcp::acceptor acceptor_;
};

class client {
public:
    explicit client(boost::asio::io_service &io_service)
        : io_service_(io_service)
        , socket_(io_service)
        , work_(new boost::asio::io_service::work(io_service))
    {
        io_service_.post(boost::bind(&client::do_init, this));
    }

    ~client() {
        packet_thread_.join(); 
    }

protected:

    void do_init() {
        // Connect to the server
        tcp::resolver resolver(io_service_);
        tcp::resolver::query query(tcp::v4(), "localhost", PORT);
        tcp::resolver::iterator iterator = resolver.resolve(query);
        socket_.connect(*iterator);

        // Start packet generation thread
        packet_thread_.swap(boost::thread(
                boost::bind(&client::generate_packets, this, 8000, 5000000)));
    }

    typedef std::vector<unsigned char> packet_type;
    typedef boost::shared_ptr<packet_type> packet_ptr;

    void generate_packets(long packet_size, long num_packets) {
        // Add a single dummy packet multiple times, then start writing
        packet_ptr buf(new packet_type(packet_size, 0));
        write_queue_.insert(write_queue_.end(), num_packets, buf);
        queue_size = num_packets;
        do_write_nolock();

        // Wait until all packets are sent.
        while (long queued = InterlockedExchangeAdd(&queue_size, 0)) {
            std::cout << "Queue size: " << queued << std::endl;
            Sleep(1000);
        }

        // Exit from run(), ignoring socket shutdown
        work_.reset();
    }

    void do_write_nolock() {
        const packet_ptr &p = write_queue_.front();
        async_write(socket_, boost::asio::buffer(&(*p)[0], p->size()),
            boost::bind(&client::on_write, this, _1));
    }

    void on_write(const error_code &ec) {
        if (ec) { throw system_error(ec); }

        write_queue_.pop_front();
        if (InterlockedDecrement(&queue_size)) {
            do_write_nolock();
        }
    }

private:
    boost::asio::io_service &io_service_;
    tcp::socket socket_;
    boost::shared_ptr<boost::asio::io_service::work> work_;
    long queue_size;
    std::list<packet_ptr> write_queue_;
    boost::thread packet_thread_;
};

int _tmain(int argc, _TCHAR* argv[]) {
    try {
        boost::asio::io_service io_svc;
        bool is_server = argc > 1 && 0 == _tcsicmp(argv[1], _T("-s"));
        std::auto_ptr<server> s(is_server ? new server(io_svc) : 0);
        std::auto_ptr<client> c(is_server ? 0 : new client(io_svc));
        io_svc.run();
    } catch (std::exception& e) {
        std::cerr << "Exception: " << e.what() << "\n";
    }
    return 0;
}
//该示例改编自async_tcp_echo_server.cpp,它是
//版权所有(c)2003-2010克里斯托弗·M·科尔霍夫(克里斯在科尔霍夫网站)
//
//以-s作为服务器启动程序
#ifndef\u WIN32\u WINNT
#定义_WIN32_WINNT 0x0501
#恩迪夫
#包括
#包括
#包括
#包括
#包括
#定义端口“1234”
使用名称空间boost::asio::ip;
使用名称空间boost::system;
课堂{
公众:
会话(boost::asio::io_服务和io_服务):套接字(io_服务){}
void do_read(){
套接字异步读取(boost::asio::buffer(数据,最大长度),
boost::bind(&session::handle_read,this,_1,_2));
}
boost::asio::ip::tcp::socket&socket(){return socket}
受保护的:
无效句柄读取(常量错误代码和ec,大小字节传输){
如果(!ec){
你读过吗;
}否则{
删除此项;
}
}
私人:
tcp::socket-socket;
枚举{max_length=1024};
字符数据[最大长度];
};
类服务器{
公众:
显式服务器(boost::asio::io_服务和io_服务)
:io_服务(io_服务)
,接受者(io_服务,tcp::端点(tcp::v4(),atoi(端口)))
{
会话*新会话=新会话(io\U服务);
acceptor\异步\u accept(新建会话->套接字(),
boost::bind(&server::handle_accept,this,new_session,_1));
}
无效句柄接受(会话*新会话、常量错误代码和ec){
如果(!ec){
新建会话->执行读取();
新会话=新会话(io\U服务);
acceptor\异步\u accept(新建会话->套接字(),
boost::bind(&server::handle_accept,this,new_session,_1));
}否则{
删除新的会议;
}
}
私人:
boost::asio::io_服务和io_服务;
boost::asio::ip::tcp::acceptor-acceptor;
};
类客户端{
公众:
显式客户端(boost::asio::io_服务和io_服务)
:io_服务(io_服务)
,套接字(io_服务)
,work_(新的boost::asio::io_服务::work(io_服务))
{
io_service_uu.post(boost::bind(&client::do_init,this));
}
~client(){
数据包线程连接();
}
受保护的:
void do_init(){
//连接到服务器
tcp::解析器解析器(io_服务);
tcp::resolver::query查询(tcp::v4(),“localhost”,端口);
tcp::resolver::iterator iterator=resolver.resolve(查询);
套接字连接(*迭代器);
//启动包生成线程
数据包线程交换(boost::thread)(
boost::bind(&client::generate_packets,this,8000500000));
}
typedef std::向量包类型;
typedef boost::共享的ptr数据包;
void生成\u数据包(长数据包大小,长数据包数量){
//多次添加单个虚拟数据包,然后开始写入
packet_ptr buf(新的packet_类型(packet_大小,0));
write_queue_uu.insert(write_queue_uu.end(),num_数据包,buf);
队列大小=num\u数据包;
你写什么;
//等待所有数据包发送完毕。
while(长队列=InterlocatedExchangeAdd(&队列大小,0)){
标准::cout
  • 调整boost::asio::socket\u base::发送缓冲区大小和接收缓冲区大小
  • 将最大长度调整为较大的数字。由于TCP是面向流的,因此不要将其视为接收单个数据包。这很可能导致TCP发送/接收窗口之间出现某种“僵局”
我最近
pSocket->set_option( boost::asio::ip::tcp::no_delay( true) );
pSocket->set_option( boost::asio::socket_base::send_buffer_size( s_SocketBufferSize ) );
pSocket->set_option( boost::asio::socket_base::receive_buffer_size( s_SocketBufferSize ) );