Domanda

Sto scrivendo server utilizzando boost.asio. Ho leggere e scrivere buffer per ciascuna connessione e l'utilizzo asincrono direttamente lettura / scrittura funzione (async_write_some / async_read_some).

Con buffer di lettura e async_read_some, non c'è nessun problema. Proprio invocando la funzione async_read_some è bene perché buffer di lettura è di sola lettura nel gestore di lettura (significa in stesso thread di solito).

Ma, un buffer di scrittura deve essere accessibile da diversi fili quindi bisogno di essere bloccato per la modifica.

PRIMA DOMANDA!

Ci sono un modo per evitare la serratura per buffer di scrittura?

Scrivo il mio pacchetto in buffer di stack e copiarlo nella buffer di scrittura. Quindi, chiamare la funzione async_write_some inviare il pacchetto. In questo modo, se io mando due pacchetti in serie, è bene che invoca la funzione async_write_some due volte?

SECONDA DOMANDA!

Qual è il modo comune per la scrittura asincrono direttamente in programmazione socket?

Grazie per la lettura.

È stato utile?

Soluzione

Risposta # 1:

Hai ragione che il blocco è una soluzione valida, ma c'è un modo molto più semplice per fare tutto questo. Boost ha un bel po 'di costrutto in ASIO chiamato strand. Qualsiasi callback che è stato avvolto utilizzando il filamento verrà serializzato, garantito, indipendentemente dal thread esegue la richiamata. In sostanza, gestisce qualsiasi blocco per voi.

Questo significa che si può avere come molti scrittori che si desidera, e se sono tutti avvolti dal stesso Strand (così, condividi la tua unico filo tra tutti i tuoi scrittori) che verranno eseguiti in modo seriale . Una cosa a cui prestare attenzione è quello di assicurarsi che non si sta tentando di utilizzare lo stesso buffer reale in memoria per fare tutte le operazioni di scrittura. Ad esempio, questo è cosa evitare:

char buffer_to_write[256];  // shared among threads

/* ... in thread 1 ... */
memcpy(buffer_to_write, packet_1, std::min(sizeof(packet_1), sizeof(buffer_to_write)));
my_socket.async_write_some(boost::asio::buffer(buffer_to_write, sizeof(buffer_to_write)), &my_callback);

/* ... in thread 2 ... */
memcpy(buffer_to_write, packet_2, std::min(sizeof(packet_2), sizeof(buffer_to_write)));
my_socket.async_write_some(boost::asio::buffer(buffer_to_write, sizeof(buffer_to_write)), &my_callback);

, stai condividendo il tuo buffer di scrittura attuale (buffer_to_write). Se avete fatto qualcosa di simile, invece, sarai a posto:

/* A utility class that you can use */
class PacketWriter
{
private:
  typedef std::vector<char>  buffer_type;

  static void WriteIsComplete(boost::shared_ptr<buffer_type> op_buffer, const boost::system::error_code& error, std::size_t bytes_transferred)
  {
    // Handle your write completion here
  }

public:
  template<class IO>
  static bool WritePacket(const std::vector<char>& packet_data, IO& asio_object)
  {
    boost::shared_ptr<buffer_type> op_buffer(new buffer_type(packet_data));

    if (!op_buffer)
    {
      return (false);
    }

    asio_object.async_write_some(boost::asio::buffer(*op_buffer), boost::bind(&PacketWriter::WriteIsComplete, op_buffer, boost::asio::placeholder::error, boost::asio::placeholder::bytes_transferred));
  }
};

/* ... in thread 1 ... */
PacketWriter::WritePacket(packet_1, my_socket);

/* ... in thread 2 ... */
PacketWriter::WritePacket(packet_2, my_socket);

Qui, sarebbe utile se hai superato il tuo filo in WritePacket pure. Si ottiene l'idea, però.

Risposta # 2:

Credo che si sta già assumendo un ottimo approccio. Un suggerimento vorrei offrire è quello di utilizzare al posto di async_write async_write_some in modo che si sono garantiti l'intero buffer è scritto prima della richiamata viene chiamato.

Altri suggerimenti

Siamo spiacenti, ma si hanno due scelte:

  1. puntate la dichiarazione di scrittura, sia con le serrature, o meglio avviare un thread di scrittura separata che legge le richieste da una coda, altri thread può quindi impilare fino richieste sul coda senza troppa contesa (alcuni mutexing sarebbe necessario).

  2. Dare ad ogni iscritto infilare la propria presa di corrente! Questo è in realtà la soluzione migliore se il programma all'altra estremità del filo può sostenerla.

Si potrebbe coda le modifiche e li eseguire sui dati del gestore di scrittura.

Rete sarebbe molto probabilmente la parte più lenta del tubo (supponendo che il modifica non sono computationaly costoso), in modo da poter eseguire mods mentre il socket layer è l'invio del dati precedenti.

In caso si sta gestendo gran numero di clienti con frequenti connessione / disconnessione un'occhiata a IO porte di completamento o meccanismo simile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top