2013-01-18 42 views
2

我有以下服務器代碼。等待客戶端連接,並且一旦客戶端連接它就會啓動從客戶端接收數據的線程,主線程將等待另一個客戶端連接。此代碼工作正常。升壓asio定時器不能阻止讀取呼叫

現在我必須指定服務器會等待一段時間說10秒,從連接的客戶端接收數據。否則服務器將在指定時間內沒有收到數據的情況下關閉通訊。我已經實現了相同的計時器,但不知何故,它不工作,並且timer_callback不會在時間流逝後調用。

#include <ctime> 
#include <iostream> 
#include <string> 
#include <boost/asio.hpp> 
#include <sys/socket.h> 
#include <unistd.h> 
#include <string> 
#include <boost/bind.hpp> 
#include <boost/thread.hpp> 
#include <boost/date_time.hpp> 

using namespace std; 
using boost::asio::ip::tcp; 

void run(boost::shared_ptr<tcp::socket> my_socket) 
{ 
    while (1) 
    { 
     char buf[128]; 
     boost::system::error_code error; 

     size_t len = my_socket->read_some(boost::asio::buffer(buf, 128), error); 
     std::cout << "len : " << len << std::endl; 

     if (error == boost::asio::error::eof) 
     { 
      cout << "\t(boost::asio::error::eof)" << endl; 
      if (my_socket->is_open()) 
      { 
       boost::system::error_code ec; 
       cout << "\tSocket closing" << endl; 
       my_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); 
       cout << "\tShutdown " << ec.message() << endl; 
       //cout << "normal close : " << ::close(my_socket->native_handle()) << endl; 
       my_socket->close(ec); 
       cout << "\tSocket closed" << endl; 
      } 
      break; // Connection closed cleanly by peer. 
     } 
     else if (error) 
     { 
      std::cout << "Exception : " << error.message() << std::endl; 
      break; 
     } 
     else 
     { 
      for (unsigned int i = 0; i < len; i++) 
       printf("%02x ", buf[i] & 0xFF); 
      printf("\n"); 
     } 
    } 
} 

void timer_callback(boost::shared_ptr<tcp::socket> my_socket, const boost::system::error_code& error) 
{ 
    std::cout << "timer expired.... " << std::endl; 
    if (error != boost::asio::error::operation_aborted) 
    { 
     // do something 
     std::string str_error = "timer expired " + error.message(); 
     my_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both); 
     my_socket->close(); 
    } 
    else 
    { 
     std::cout << "timer cancelled ..." << error.message() << std::endl; 
    } 
} 

int main() 
{ 
    const int S = 1000; 
    vector<boost::shared_ptr<boost::thread> > arr_thr(S); 
    boost::asio::io_service io_service; 
    boost::asio::deadline_timer timer(io_service); 

    try 
    { 
     for (uint32_t i = 0;; i++) 
     { 

      tcp::endpoint endpoint(tcp::v6(), 10001); 

      boost::shared_ptr<tcp::socket> my_socket(new tcp::socket(io_service)); 
      tcp::endpoint end_type; 

      tcp::acceptor acceptor(io_service, endpoint); 

      std::cout << "before accept" << endl; 
      acceptor.accept(*my_socket, end_type); 

      usleep(10000); 

      std::cout << "connected... hdl : " << my_socket->native_handle() << std::endl; 

      boost::asio::ip::address addr = end_type.address(); 
      std::string sClientIp = addr.to_string(); 

      std::cout << "\tclient IP : " << sClientIp << std::endl; 

      timer.expires_from_now(boost::posix_time::seconds(10)); 
      timer.async_wait(
        boost::bind(&timer_callback, my_socket, boost::asio::placeholders::error)); 

      arr_thr[i] = boost::shared_ptr<boost::thread>(new boost::thread(&run, my_socket)); 
     } 
    } catch (std::exception& e) 
    { 
     std::cerr << e.what() << std::endl; 
    } 

    return 0; 
} 

回答

3

它看起來像你想要做在主線程的acceptasync_wait,做一些阻擋在單獨的線程讀取。

有多種問題,這種做法。首先你的accept被阻塞,所以定時器在主線程等待接受時不能運行。也沒有呼叫io_servicerunpoll,所以異步處理程序將永遠不會被調用。

你必須使用async_accept如果你想將它與async_wait在同一個線程混合。

但是您仍然無法取消另一個線程讀取的阻塞。 documentation指出同時使用來自多個線程的套接字是不安全的(共享對象:不安全)。

我會建議你使用完全異步設計。

+0

嗨,我同意你的使用完全異步設計的建議,但問題是,一旦我使用io_service.stop()io_service.reset(),然後io_service.run()給出了錯誤。 –

+2

這是因爲有待處理的異步操作。 只需設計它即可停止服務器,當您要退出時停止發出任何異步操作或放棄有關異步掛起操作的錯誤。 – geekpp

+1

通常,您不要在簡單的服務器中使用'io_service :: stop()'和'io_service :: reset()'。查看文檔中的示例以獲取異步服務器示例代碼。 – jcm