2017-08-10 113 views
1

我正在嘗試爲boost套接字實現ConnectWithTimeout函數。所以我使用了我發現的其中一個例子here。這在第一次嘗試中完美工作,但io_service.run_one()立即返回超時或取消錯誤。boost io_service不重置

這裏是我的代碼

using NetStatus = boost::system::error_code; 

NetStatus handleWait(const NetStatus& error) 
{ 
    return boost::asio::error::timed_out; 
} 

NetStatus handleConnect(const NetStatus& error) 
{ 
    // The async_connect() function automatically opens the socket at the start 
    // of the asynchronous operation. If the socket is closed at this time then 
    // the timeout handler must have run first. 
    if (!m_socket.is_open()) 
     return boost::asio::error::timed_out; 

    // Otherwise, a connection has been established. Update the timer state 
    // so that the timeout handler does not close the socket. 
    m_connectionTimeoutTimer.cancel(); 
    return error; 
} 

void connectWithTimeout(boost::asio::ip::tcp::endpoint& endpoint, NetStatus& e) 
{ 
    // Stop last time's waiting objects 
    m_socket.cancel() 
    m_connectionTimeoutTimer.cancel(); 
    m_ioService.stop(); 
    m_ioService.reset(); 

    // Set-up new objects to wait 
    m_connectionTimeoutTimer.expires_from_now(boost::posix_time::seconds(5)); 
    m_connectionTimeoutTimer.async_wait([this, &e](const NetStatus& error) { e = handleWait(error); }); 
    m_socket.async_connect(endpoint, [this, &e](const NetStatus& error) { e = handleConnect(error); }); 

    // Block until one of them is done 
    m_ioService.run_one(e); 
} 

boost::asio::ip::tcp::socket m_socket; 
boost::asio::deadline_timer m_connectionTimeoutTimer; 

循環運行這個時,我看到的結果是: 超時(5秒後如預期) 取消(立即) 超時(立即) 取消(立即) 超時(立即) 取消(立即) 超時(立即) ...

誰能請幫助我們發現自己在做什麼wron G?

+0

我不爲什麼已瞭解你打電話'm_ioService.stop();'和'm_ioService.reset();''裏面connectWithTimeout()'函數 –

+0

我試圖讓io_service停止從前一次運行中彈出事件,所以我確保沒有以前的處理程序正在等待運行重置和停止。 –

回答

0

你是否關閉每個循環之間的套接字?您可以在同一個m_socket實例上調用async_connect,但我沒有看到套接字關閉的位置。您可能在嘗試連接已打開的套接字時出現錯誤。嘗試m_socket.close()而不是m_socket.cancel()

+0

我用你提示的m_socket.close()替換了m_socket.cancel(),並得到了和前面相同的結果 –

0

好的,所以我找到了答案,看來只有從io_service獲取處理程序的唯一方法是用run或run_one調用它,重置等不會。是最後的代碼,我得到了,如果有人有興趣:

#include <iostream> 
#include <string> 
#include <boost/asio.hpp> 
#include <boost/filesystem.hpp> 
#include <boost/iostreams/filtering_streambuf.hpp> 
#include <boost/iostreams/copy.hpp> 
#include <boost/iostreams/filter/gzip.hpp> 
#include <boost/timer/timer.hpp> 

std::string bindToIp; 
std::string ip; 
int   port; 
auto tcpConnectionTrials = 5ul; 

using NetStatus = boost::system::error_code; 

boost::asio::io_service m_ioService; 
boost::asio::ip::tcp::socket m_socket(m_ioService); 
boost::asio::deadline_timer connectionTimeoutTimer(m_ioService); 
bool isTimedOut = false; 

void handleWait(boost::asio::ip::tcp::socket& socket, const NetStatus& error) 
{ 
     if (error != boost::asio::error::operation_aborted) 
     { 
       isTimedOut = true; 
       socket.cancel(); 
       socket.close(); 
     } 
} 

void handleConnect(boost::asio::ip::tcp::socket& socket, const NetStatus& error) 
{ 
     if (error != boost::asio::error::operation_aborted) 
     { 
       // The async_connect() function automatically opens the socket at the start 
       // of the asynchronous operation. If the socket is closed at this time then 
       // the timeout handler must have run first. 
       if (socket.is_open()) 
       { 
         connectionTimeoutTimer.cancel(); 
       } 
     } 
} 


void connectWithTimeout(boost::asio::ip::tcp::socket& socket, 
               boost::asio::deadline_timer& connectionTimeoutTimer, 
               boost::asio::io_service& m_ioService, 
               boost::asio::ip::tcp::endpoint& endpoint, 
               NetStatus& e) 
{ 
     isTimedOut = false; 

     // Set-up new objects to wait 
     connectionTimeoutTimer.expires_from_now(boost::posix_time::seconds(5)); 
     connectionTimeoutTimer.async_wait([&socket](const NetStatus& error)  { handleWait(socket, error); }); 
     socket.async_connect(endpoint, [&socket, &e](const NetStatus& error) { e = error; handleConnect(socket, error); }); 

     // Block until one of them is done 
     m_ioService.run(); 
     if (isTimedOut) 
     { 
       e = boost::asio::error::timed_out; 
     } 
     m_ioService.reset(); 
} 

NetStatus connect() 
{ 
     NetStatus e; 

     boost::asio::ip::tcp::endpoint remoteEndpoint(boost::asio::ip::address_v4::from_string(ip.c_str()), port); 
     boost::asio::ip::tcp::endpoint localEndpoint(boost::asio::ip::address_v4::from_string(bindToIp.c_str()), 0); 

     std::cout << "Open socket: " << std::endl; 
     if (m_socket.open(boost::asio::ip::tcp::v4(), e)) 
     { 
       std::cout << "Socket " << ": could not open!!!" << std::endl; 
       return e; 
     } 
     m_socket.set_option(boost::asio::socket_base::reuse_address(true)); 
     m_socket.set_option(boost::asio::ip::tcp::no_delay(true)); 

     std::cout << " binds to " << bindToIp << std::endl; 
     m_socket.bind(localEndpoint); 

     std::cout << " connect to " << ip << std::endl; 
     connectWithTimeout(m_socket, connectionTimeoutTimer, m_ioService, remoteEndpoint, e); 
     return e; 
} 

int main(int argc, char *argv[]) 
{ 
     bindToIp = argv[1]; 
     ip = argv[2]; 
     port = atoi(argv[3]); 

     for(int i =0; i < 10; i++) 
     { 
       auto e = connect(); 
       if (!e) 
       { 
         std::cout << "GOOD!" << std::endl; 
         break; 
       } 
       else 
       { 
         std::cout << "Failed: " << e.message() << std::endl; 
       } 
       m_socket.close(); 
     } 
     std::cout << "DONE!" << std::endl; 
     return 0; 
} 
+0

我發現該機制應該並且確實可行!這不是提升,而是一個驅動程序問題,因爲我使用了一個特殊的驅動程序來提高插槽性能。 –

相關問題