2013-02-25 16 views
6

Ho le due seguenti funzioni per l'invio e la ricezione di pacchetti.boost :: asio :: buffer: recupero della dimensione del buffer e prevenzione dell'overflow del buffer?

void send(std::string protocol) 
{ 
    char *request=new char[protocol.size()+1]; 
    request[protocol.size()] = 0; 
    memcpy(request,protocol.c_str(),protocol.size()); 

    request_length = std::strlen(request); 
    boost::asio::write(s, boost::asio::buffer(request, request_length)); 
} 
void receive() 
{ 
    char reply[max_length]; 
    size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length)); 
    std::cout << "Reply is: "; 
    std::cout.write(reply, reply_length); 
    std::cout << "\n"; 
} 

Le domande riguardano questa parte boost::asio::buffer(reply, request_length) cui la lunghezza richiesta è la lunghezza di una stringa che inizialmente era configurazione quando il pacchetto è stato inviato. Come posso controllare la dimensione del buffer senza conoscere request_length? Un'altra domanda è come impedire l'overflow del buffer?

risposta

15

Per ottenere le dimensioni di un buffer, è possibile utilizzare la funzione boost::asio::buffer_size(). Tuttavia, nel tuo esempio, questo probabilmente ti sarà poco utile.

Come spiegato nel buffer overview, Boost.Asio utilizza le classi del buffer per rappresentare i buffer. Queste classi forniscono un'astrazione e proteggono le operazioni Boost.Asio contro i sovraccarichi del buffer. Sebbene il risultato di boost::asio::buffer() venga passato alle operazioni, i metadati, come la dimensione del buffer o il tipo sottostante, non vengono trasmessi. Inoltre, questi buffer non possiedono la memoria, quindi è responsabilità delle applicazioni assicurare che la memoria sottostante rimanga valida per tutta la durata della vita dell'astrazione del buffer.

La funzione boost::asio::buffer() fornisce un modo conveniente per creare le classi di buffer, in cui la dimensione del buffer viene dedotta dal tipo possibile. Quando Boost.Asio è in grado di dedurre la lunghezza del buffer, le operazioni Boost.Asio non invocheranno un overflow del buffer quando si utilizza il tipo di buffer risultante. Tuttavia, se il codice dell'applicazione specifica la dimensione del buffer su boost::asio::buffer(), è responsabilità delle applicazioni assicurarsi che la dimensione non sia maggiore della memoria sottostante.

Durante la lettura dei dati, è richiesto un buffer. La domanda fondamentale diventa come si fa a sapere quanta memoria allocare, se Boost.Asio non trasmette la dimensione. Ci sono alcune soluzioni a questo problema:

  • Query la presa per la quantità di dati è disponibile tramite socket::available(), quindi allocare il buffer di conseguenza.

    std::vector<char> data(socket_.available()); 
    boost::asio::read(socket_, boost::asio::buffer(data)); 
    
  • utilizzare una classe che Boost.Asio può crescere in memoria, come ad esempio boost::asio::streambuf. Alcune operazioni, ad esempio boost::asio::read() accettano gli oggetti streambuf come buffer e allocano la memoria come richiesto per l'operazione. Tuttavia, dovrebbe essere fornita una condizione di completamento; in caso contrario, l'operazione continuerà fino a quando il buffer non sarà pieno.

    boost::asio::streambuf data; 
    boost::asio::read(socket_, data, 
            boost::asio::transfer_at_least(socket_.available())); 
    
  • Come suggerisce Öö Tiib, incorporare lunghezza come parte del protocollo di comunicazione. Controlla Boost.Asio examples per esempi di protocolli di comunicazione. Concentrati sul protocollo, non necessariamente sul Boost.Asio API.

    • In un protocollo di dimensioni fisse, sia il produttore di dati che il consumatore utilizzano lo stesso messaggio di dimensione. Poiché il lettore conosce la dimensione del messaggio, il lettore può allocare un buffer in anticipo.
    • In un protocollo di lunghezza variabile, i messaggi sono spesso divisi in due parti: un'intestazione e un corpo. L'intestazione è in genere di dimensioni fisse e può contenere varie meta-informazioni, come la lunghezza del corpo. Ciò consente a un lettore di leggere un'intestazione in un buffer di dimensioni fisse, estrarre la lunghezza del corpo, allocare un buffer per il corpo, quindi leggere il corpo.

      // Read fixed header. 
      std::vector<char> data(fixed_header_size); 
      boost::asio::read(socket_, boost::asio::buffer(data)); 
      
      protocol::header header(data); 
      network_to_local(header); // Handle endianess. 
      
      // Read body. 
      data.resize(header.body_length()); 
      boost::asio::read(socket_, boost::asio::buffer(data)); 
      
      protocol::body body(data); 
      network_to_local(body); // Handle endianess.  
      
+0

Grandi cose. 'boost :: asio :: streambuff' con' boost :: asio :: read_until() 'ha funzionato bene nel caso in cui i messaggi terminassero con un delimitatore. –

1

Penso che la tua domanda è confusa, ma questo potrebbe aiutare:

void receive() { 
    enum { max_length = 1024 }; 
    char reply[max_length]; 
    size_t reply_length; 
    std::cout << "Reply is: "; 
    while ((reply_length = ba::read(s, basio::buffer(reply, max_length))) > 0) { 
    std::cout.write(reply, reply_length); 
    } 
    std::cout << "\n"; 
} 
+0

Il 'boost :: asio :: tampone (,)' restituisce cosa esattamente. Vedo che restituisce qualcosa nel 'ba :: read (s, buffer (,))' ma che cos'è? – pandoragami

+0

@lost_with_coding: un tipo che rappresenta la memoria, ma non possiede la memoria. La [funzione] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/buffer.html) consente di adattare i tipi di uso comune in modo che soddisfino i requisiti di tipo per molti dei Boost . Operazioni Asio. Questa [panoramica] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/overview/core/buffers.html) fornisce alcune informazioni. –

+0

In questo esempio non è necessario passare max_length a asio :: buffer(). (Dal momento che asio può ottenerlo usando 'sizeof'.) –

5

Tipicamente un protocollo di comunicazione o utilizza i messaggi di lunghezza fissa o messaggi che contengono un'intestazione che racconta la lunghezza del messaggio.

Boost.Asio online documentation contiene un ampio set di esempi ed esercitazioni quindi è consigliabile iniziare da lì. Wikipedia è una buona fonte per spiegare la terminologia data transmission, aumentare la documentazione asio non lo fa.

+1

Ho già guardato attraverso i tutorial di boost, ma questi semplicemente sorvolano gli esempi e non spiegano in modo dettagliato cosa fanno le funzioni, cosa restituiscono, ecc. So che potrei esaminare anche i file hpp ma è come un ago nel pagliaio e ancora più inutile degli esempi stessi. Sono sicuro che ci sono molte cose non dette negli esempi di boost/tutorial ma che si trovano solo nei file hpp che potrebbero richiedere anni di pratica. – pandoragami

+0

@lost_with_coding forse gli esempi di boost asio si aspettano che le persone abbiano familiarità con il concetto di comunicazione digitale e il significato di termini correlati come protcoli, client, server, richieste ecc. Utilizzati negli esempi. Io suggerisco di evitare il reverse engineering di tali conoscenze dal codice, ci sono fonti più facili per imparare tutto questo. –

+0

@lost_with_coding: Gli [esempi] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/examples.html) non spiegano cosa fa l'API perché ciò è documentato nel [riferimento ] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference.html) sezione. La libreria Boost.Asio è complessa, non complicata. C'è una grande quantità di informazioni nella documentazione e potrebbe valere la pena prendersi il tempo necessario per familiarizzare con le varie parti della documentazione. –

Problemi correlati