2013-02-22 63 views
0

簡介:C++ boost asio |同步寫入異步讀取|無法在第二次收到正確的數據讀取

我想用C++做一個服務器/客戶端應用程序和boost :: ASIO,我也想使同步在對方收到寫入以連續的異步讀取結束。 例如我的服務器異步讀取固定字節長度的數據流,然後移動到由客戶端同步寫入發送的下一個字節。

問題:

在連續異步

讀取字節被正確地讀出的第一個流,但是當它繼續到下一個異步讀的東西從另一端發送具有相同字節長度我excpecting但它是垃圾或我不能將其轉換爲有價值的數據。

驗證碼:

private: 
     static const int MAX_MTU = 1500; //Ethernet Maximum Transfer UNIT (MTU)... 
     static const int TRASH_CAN = 100; //Amount to substract from the MAX_MTU to make room for basic packet structure elements. 
     static const int BUFFER_SIZE = MAX_MTU - TRASH_CAN; 
     boost::mutex mutex; 
     typedef char* data_bytes; 
     std::list<data_bytes> data; 

    private: 
     tcp::socket socket_; 
     boost::asio::io_service& io_service_; 
     moqane::tcp_packet *packet_; 

    // CTOR for the incoming connection from a client to the server 
    public: tcp_session(boost::asio::io_service& io_service) 
     : io_service_(io_service), 
     socket_(io_service), 
     packet_(new moqane::tcp_packet()) 
    { 
     // ...... 
    } 

    // CTOR for the outgoing clinet connection to the server... 
    public: tcp_session(boost::asio::io_service& io_service, tcp::resolver::iterator endpoint_iterator) 
     : io_service_(io_service), 
     socket_(io_service), 
     packet_(new moqane::tcp_packet()) 
    { 
     boost::asio::async_connect(socket_, 
            endpoint_iterator, 
            boost::bind(&tcp_session::connect_to_server_hndlr, 
               this, 
               boost::asio::placeholders::error) 
            ); 
    } 

    tcp::socket& socket() 
    { 
     return socket_; 
    } 

    public: 
    void read_header() 
    { 

     read_packet(packet_->HEADER_LENGTH, 
        boost::bind(
          &moqane::tcp_session::read_header_hndlr, 
          shared_from_this(), 
          packet_->HEADER_LENGTH, 
          boost::asio::placeholders::error) 
        ); 
    } 

    private: 
    void connect_to_server_hndlr(const boost::system::error_code& error) 
    { 
     if (!error) 
     { 
      read_header(); 
     } 
     else 
     { 
      // TODO: fire the error event... 
     } 
    } 

    private: 
    template <class T> 
    void read_packet(int packet_length, T handler) 
    { 
     /* 
     Packet Structure: (Mohamed Tarek (moqane)) 
     ============================================================================================== 
     HEADER: could be a 3 or 4 bytes that give enough information to the endpoint on how to receive 
       those bytes. 
     SIZE : A 4 byte-length number that tell the endpoint how much data in bytes ar comming. 
       ex: 0340 which should tell us that the incoming data are 340 bytes, so we will not 
       receive more or less than that. 
     DATA : the incoming valuable information that we want to receive in the first place. 

     --------------------------------------------- 
     |  |  |       | 
     | HEADER | SIZE | DATA...     | ----> PACKET 
     | 3b | 4b | N/A b      | 
     ---------------------------------------------- 
     ============================================================================================== 
     */ 

     if (data.size() > 0) 
     { 
      data.clear(); 
     } 

     char d[moqane::tcp_session::BUFFER_SIZE]; 
     data.push_back(d); 
     boost::asio::async_read(socket_, 
           boost::asio::buffer(data.back(), packet_length), 
           handler 
           ); 
    } 

    private: 
    void write_packet(char* data_bytes) 
    { 
     boost::asio::write(socket_, boost::asio::buffer(data_bytes, sizeof(data_bytes))); 

    } 

    private: 
    void write_packet_hndlr(const boost::system::error_code& error) 
    { 
     if (!error) 
     { 
     } 
     else 
     { 
     } 
    } 


    private: 
    void read_header_hndlr(int packet_length, const boost::system::error_code& error) 
    { 
     if (!error) 
     { 
      // convert bytes to wxstring 
      // wxString s = moqane::wx2string::To_wxString(packet_->DATA(), packet_->HEADER_LENGTH()); 

      // convert our bytes to string 
      std::string header(data.back(), packet_length); 

      if (packet_->is_header(header)) 
      { 
       // read the SIZE packet 
       read_packet(packet_->SIZE_LENGTH, 
          boost::bind(
            &moqane::tcp_session::read_size_hndlr, 
            shared_from_this(), 
            packet_->SIZE_LENGTH, 
            header, 
            "", 
            boost::asio::placeholders::error) 
          ); 
      } 
      else 
      { 
       // reread the HEADER packet if it's not a valid header 
       read_header(); 
      } 
     } 

     else 
     { 
      // TODO: fire the error event... 
     } 



    } 

    private: 
    void read_size_hndlr(int packet_length, std::string header, std::string info, const boost::system::error_code& error) 
    { 
     if (!error) 
     { 
      std::string str_length(data.back(), packet_length); 

      int next_packet_length = moqane::number2string::ToInt(str_length); 

      if (next_packet_length > 0) 
      { 
       if (header == packet_->HEADER_STRING) 
       { 
        read_packet(next_packet_length, 
           boost::bind(
             &moqane::tcp_session::read_STRING_hndlr, 
             shared_from_this(), 
             next_packet_length, 
             boost::asio::placeholders::error) 
           ); 
       } 
       else if (header == packet_->HEADER_COMMAND) 
       { 

       } 
       else 
       { 
        // reread the HEADER packet if it's not a valid header 
        read_header(); 
       } 
      } 
      else 
      { 
       // reread the HEADER packet if it's not a valid size 
       read_header(); 
      } 
     } 
     else 
     { 
      // TODO: fire the error event... 
     } 
    } 

    private: 
    void read_STRING_hndlr(int packet_length, const boost::system::error_code& error) 
    { 
     std::string std_str(data.back(), packet_length); 
     std::string v = ""; 
    } 

    public: 
    void write_STRING(char* string_data) 
    { 
     boost::mutex::scoped_lock lock(mutex); 
     { 
      write_packet(moqane::number2string::To_CharArray("STR")); 
      write_packet(moqane::number2string::To_CharArray("xxx1")); 
      write_packet(moqane::number2string::To_CharArray("a")); 
     } 
    } 

}; 

回答

3

我懷疑問題出在read_packet

char d[moqane::tcp_session::BUFFER_SIZE]; 
    data.push_back(d); 
    boost::asio::async_read(socket_, 
          boost::asio::buffer(data.back(), packet_length), 
          handler 
          ); 

這是創建一個緩衝區d,在一個局部變量。然後將一個指向d的指針放入data,然後用它來形成async_read的緩衝區。您然後離開該功能。這會導致數組被銷燬,並有幾個懸掛指針,包括async_read。

我會建議爲頭部創建緩衝區,將其命名爲'header',以便成爲您班級的一部分。我不確定你需要單獨的data載體。

+0

我現在就嘗試,讓你知道,謝謝。 – 2013-02-22 17:49:09

+0

對不起,當我把'char data [BUFFER_SIZE];'作爲全局變量時,第二次讀取(在'read_size_hndlr')接收垃圾字節或一些不可讀的字符,並且返回的字符串總是空的。 – 2013-02-22 17:57:01

+0

問題解決了它是由於'packet_length'由'sizeof'獲得錯誤的字符長度*造成的。 – 2013-02-22 23:51:02

0

現在已經解決了,主要問題是在發送時構造緩衝區時出錯packet_length。因爲我得到的長度是sizeof(),根據我的處理器架構總是返回4。所以我現在得到char *的長度,使用下面的函數。

public: 
    static int CharArray_Length(char* somedata) 
    { 
     std::list<char> l; 

     while(*somedata != 0) 
      l.push_back(*somedata++); 

     // If you want to add a terminating NULL character 
     // in your list, uncomment the following statement: 
     // l.push_back(0); 

     return l.size(); 
    } 

參考:https://stackoverflow.com/a/15034741/1301186

+0

如果您只是想確定以空字符結尾的字符串的長度,請使用std :: strlen(somedata)。創建一個列表只是爲了獲得它的大小是低效率的,並且掩蓋了你想要做的事情。 – rhashimoto 2013-03-01 23:50:49

相關問題