boost :: asio tcp async_read永远不会返回

问题描述:

我想转换一些现有的代码来使用boost的asio tcp套接字,而不是我们当前的实现。我可以从boost网站获得一个非常类似的示例(of a chat client/server),但是当我尝试将代码放入我自己的程序中时,它停止工作。boost :: asio tcp async_read永远不会返回

我在做什么:

  1. 启动一个服务器进程
  2. 服务器进程,使闲置插槽,并用它来听(使用TCP ::受体)的端口上的TCP连接(10010例如)
  3. 启动客户端进程
  4. 在客户端过程中创建一个套接字连接到服务器的端口
  5. 当服务器看到一个客户端连接,它开始侦听数据(与async_read )并创建另一个空的套接字来侦听端口上的另一个TCP连接
  6. 当客户端发现服务器已连接时,它会发送100个字节的数据(使用async_write)并等待套接字告诉它发送完毕......这种情况发生时它打印一条消息,并关闭
  7. 当服务器被通知其具有已被读取数据时,它显示一条消息,并关闭

很显然,我有从我试图实现的内容中大大削减了这些代码,这只是我能够做出重现问题的事情的一小部分。我在Windows上运行,并有一个视觉演播室解决方案文件,您可以get。有一些内存泄漏,线程安全问题等等,但那是因为我正在从现有的代码中取出东西,所以不要担心它们。

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

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

我四处搜寻了一下,但还没有祝你好运。据我所知,我几乎完全匹配样本,所以它必须是我忽略的一些小东西。

谢谢!

+0

哪一方不异步读有去无回? – ergosys 2010-05-20 19:53:08

在您的客户端代码中,您的ConnectHandler()回调函数只是设置一个值然后返回,而不会将任何更多工作发布到io_service。那时,async_connect()操作是与io_service关联的唯一工作;所以当ConnectHandler()返回时,没有更多的工作与io_service相关联。因此后台线程调用io_service.run()返回,线程退出。

一个潜在的选择是调用conn->AsyncReceive()ConnectHandler()内,使async_read()ConnectHandler()之前被调用返回,因此后台线程对io_service.run()调用将不会返回。

另一种选择,更微不足道的,将是之前创建的线程调用io_service对象::运行(技术上实例化一个io_service对象::工作情况下,你可以这样做在io_service.run()调用的任何点返回):

... 
// some point in the main() method, prior to creating the background thread 
boost::asio::io_service::work work(io_service) 
... 

这是io_service对象文档中记载:

用尽工作停止io_service对象

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

http://www.boost.org/doc/libs/1_43_0/doc/html/boost_asio/reference/io_service.html