2013-02-22 62 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

相关问题