boost::asio tcp异步\u读取永远不会返回

boost::asio tcp异步\u读取永远不会返回,boost,tcp,boost-asio,Boost,Tcp,Boost Asio,我试图将一些现有代码转换为使用boost的asio tcp套接字,而不是我们当前的实现。我可以从boost站点获得一个非常类似的示例(),但是当我尝试将代码放入自己的程序时,它就停止工作了 我在做什么: 启动服务器进程 服务器进程生成一个空套接字,并使用它(使用tcp::acceptor)侦听端口上的tcp连接(例如10010) 启动客户端进程 让客户端进程创建一个连接到服务器端口的套接字 当服务器看到客户端正在连接时,它开始侦听套接字上的数据(使用async_read),并创建另一个空套接字来

我试图将一些现有代码转换为使用boost的asio tcp套接字,而不是我们当前的实现。我可以从boost站点获得一个非常类似的示例(),但是当我尝试将代码放入自己的程序时,它就停止工作了

我在做什么:

  • 启动服务器进程
  • 服务器进程生成一个空套接字,并使用它(使用tcp::acceptor)侦听端口上的tcp连接(例如10010)
  • 启动客户端进程
  • 让客户端进程创建一个连接到服务器端口的套接字
  • 当服务器看到客户端正在连接时,它开始侦听套接字上的数据(使用async_read),并创建另一个空套接字来侦听端口上的另一个TCP连接
  • 当客户端看到服务器已连接时,它会发送100字节的数据(使用async_write),并等待套接字通知它发送完成……当这种情况发生时,它会打印一条消息并关闭
  • 当服务器收到已读取其数据的通知时,它将打印一条消息并关闭
  • 很明显,我已经从我试图实现的代码中大幅缩减了这段代码,这是我能够制造出重现问题的东西的最小部分。我在windows上运行,有一个visual studio解决方案文件,您可以使用。存在一些内存泄漏、线程安全问题等等,但这是因为我从现有代码中提取了一些内容,所以不要担心它们

    无论如何,这里有一个文件头和一些常见的东西,一个服务器和一个客户端

    Connection.hpp:

    
    #ifndef CONNECTION_HPP
    #define CONNECTION_HPP
    #include 
    #include 
    #include 
    
    class ConnectionTransfer
    {
    public:
       ConnectionTransfer(char* buffer, unsigned int size) :
          buffer_(buffer), size_(size)   {
       }
       virtual ~ConnectionTransfer(void){}
    
       char* GetBuffer(){return buffer_;}
       unsigned int GetSize(){return size_;}
    
       virtual void CallbackForFinished() = 0;
    
    protected:
       char* buffer_;
       unsigned int size_;
    };
    
    class ConnectionTransferInProgress
    {
    public:
       ConnectionTransferInProgress(ConnectionTransfer* ct):
          ct_(ct)
       {}
       ~ConnectionTransferInProgress(void){}
    
       void operator()(const boost::system::error_code& error){Other(error);}
       void Other(const boost::system::error_code& error){
          if(!error)
             ct_->CallbackForFinished();
       }
    private:
       ConnectionTransfer* ct_;
    };
    
    class Connection 
    {
    public:
       Connection(boost::asio::io_service& io_service):
       sock_(io_service)
       {}
       ~Connection(void){}
       void AsyncSend(ConnectionTransfer* ct){
          ConnectionTransferInProgress tip(ct);
          //sock_->async_send(boost::asio::buffer(ct->GetBuffer(), 
          //   static_cast(ct->GetSize())), tip);
          boost::asio::async_write(sock_, boost::asio::buffer(ct->GetBuffer(), 
             static_cast(ct->GetSize())), boost::bind(
             &ConnectionTransferInProgress::Other, tip, boost::asio::placeholders::error));
       }
       void AsyncReceive(ConnectionTransfer* ct){
          ConnectionTransferInProgress tip(ct);
          //sock_->async_receive(boost::asio::buffer(ct->GetBuffer(), 
          //   static_cast(ct->GetSize())), tip);
          boost::asio::async_read(sock_, boost::asio::buffer(ct->GetBuffer(), 
             static_cast(ct->GetSize())), boost::bind(
             &ConnectionTransferInProgress::Other, tip, boost::asio::placeholders::error));
       }
    
       boost::asio::ip::tcp::socket& GetSocket(){return sock_;}
    private:
       boost::asio::ip::tcp::socket sock_;
    };
    #endif //CONNECTION_HPP
    
    BoostConnectionClient.cpp:

    
    #include "Connection.hpp"
    
    #include 
    #include 
    #include 
    #include 
    
    using namespace boost::asio::ip;
    
    bool connected;
    bool gotTransfer; 
    
    class FakeTransfer : public ConnectionTransfer
    {
    public:
       FakeTransfer(char* buffer, unsigned int size) : ConnectionTransfer(buffer, size)
       {
       }
       void CallbackForFinished()
       {
          gotTransfer = true;
       }
    };
    
    void ConnectHandler(const boost::system::error_code& error)
    {
       if(!error)
          connected = true;
    }
    
    int main(int argc, char* argv[])
    {
       connected = false;
       gotTransfer = false;
       
       boost::asio::io_service io_service;
    
       Connection* conn = new Connection(io_service);
    
       tcp::endpoint ep(address::from_string("127.0.0.1"), 10011);
       conn->GetSocket().async_connect(ep, ConnectHandler);
       
       boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
    
       while(!connected)
       {
          boost::this_thread::sleep(boost::posix_time::millisec(1));
       }
       std::cout (angle brackets here) "Connected\n";
    
       char data[100];
       FakeTransfer* ft = new FakeTransfer(data, 100);
       conn->AsyncReceive(ft);
    
       while(!gotTransfer)
       {
          boost::this_thread::sleep(boost::posix_time::millisec(1));
       }
       
       std::cout (angle brackets here) "Done\n";
    
       return 0;
    }
    
    
    BoostConnectionServer.cpp:

    
    #include "Connection.hpp"
    
    #include 
    #include 
    #include 
    #include 
    
    using namespace boost::asio::ip;
    
    Connection* conn1;
    bool conn1Done;
    bool gotTransfer;
    Connection* conn2;
    
    class FakeAcceptor
    {
    public:
       FakeAcceptor(boost::asio::io_service& io_service, const tcp::endpoint& endpoint)
          : 
          io_service_(io_service),
          acceptor_(io_service, endpoint)
      {
          conn1 = new Connection(io_service_);
          acceptor_.async_accept(conn1->GetSocket(),  
             boost::bind(&FakeAcceptor::HandleAccept, this, conn1, 
             boost::asio::placeholders::error));
       }
       void HandleAccept(Connection* conn, const boost::system::error_code& error)
       {
          if(conn == conn1)
             conn1Done = true;
          conn2 = new Connection(io_service_);
          acceptor_.async_accept(conn2->GetSocket(),  
             boost::bind(&FakeAcceptor::HandleAccept, this, conn2, 
             boost::asio::placeholders::error));
       }
       boost::asio::io_service& io_service_;
       tcp::acceptor acceptor_;
    };
    
    class FakeTransfer : public ConnectionTransfer
    {
    public:
       FakeTransfer(char* buffer, unsigned int size) : ConnectionTransfer(buffer, size)
       {
       }
       void CallbackForFinished()
       {
          gotTransfer = true;
       }
    };
    
    int main(int argc, char* argv[])
    {
       boost::asio::io_service io_service;
       conn1Done = false;
       gotTransfer = false;
       tcp::endpoint endpoint(tcp::v4(), 10011);
       FakeAcceptor fa(io_service, endpoint);
       boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
    
       while(!conn1Done)
       {
          boost::this_thread::sleep(boost::posix_time::millisec(1));
       }
       std::cout (angle brackets here) "Accepted incoming connection\n";
    
       char data[100];
       FakeTransfer* ft = new FakeTransfer(data, 100);
       conn1->AsyncReceive(ft);
    
       while(!gotTransfer)
       {
          boost::this_thread::sleep(boost::posix_time::millisec(1));
       }
       std::cout (angle brackets here) "Success!\n";
       return 0;
    }
    
    我四处找了一下,但运气不太好。据我所知,我几乎完全符合样本,所以我一定忽略了一些小东西


    谢谢

    在客户端代码中,您的
    ConnectHandler()
    回调函数只设置一个值,然后返回,而不向io_服务发布任何更多工作。此时,
    async\u connect()
    操作是与io\u服务相关的唯一工作;因此,当
    ConnectHandler()
    返回时,就不再有与io_服务相关的工作了。因此,后台线程对
    io\u service.run()
    的调用返回,线程退出

    一个可能的选项是从
    ConnectHandler()
    中调用
    conn->AsyncReceive()
    ,这样在
    ConnectHandler()
    返回之前调用
    async\u read()
    ,因此后台线程对
    io\u service.run()
    的调用将不会返回

    另一个更简单的选项是,在创建调用io_service::run的线程之前实例化io_service::work实例(从技术上讲,您可以在
    io_service.run()
    调用返回之前的任何时候执行此操作):

    这在io_服务文档中有记录:

    正在停止io_服务以防止其工作耗尽

    有些应用程序可能需要防止io_服务对象的run()调用在没有更多工作要做时返回。例如,io_服务可能在应用程序异步操作之前启动的后台线程中运行。可以通过创建io_service::work类型的对象来保持run()调用的运行:


    异步读取在哪一侧永远不会返回?
    ...
    // some point in the main() method, prior to creating the background thread
    boost::asio::io_service::work work(io_service)
    ...