2012-10-07 11 views
5

Sto scrivendo un server in Linux che dovrà supportare operazioni di lettura/scrittura simultanee da più client. Voglio usare lo selezionare la funzione per gestire la disponibilità di lettura/scrittura.Qual è il vantaggio dell'utilizzo di socket non bloccanti con la funzione "select"?

Quello che non capisco è questo: Supponiamo di voler aspettare che un socket abbia dati disponibili per essere letto. La documentazione per seleziona indica che blocca fino a quando non ci sono dati disponibili da leggere e che la funzione di lettura non verrà bloccata.

Quindi, se sto usando select e so che la funzione di lettura non bloccherà, perché dovrei impostare i miei socket su non-blocking?

risposta

6

Ci possono essere casi in cui un socket viene segnalato come pronto ma al momento in cui viene controllato, cambia il suo stato.

Uno dei buoni esempi è l'accettazione delle connessioni. Quando arriva una nuova connessione, un socket di ascolto viene segnalato come pronto per la lettura. Nel momento in cui si arriva a chiamare accettare, la connessione potrebbe essere chiusa dall'altro lato prima di inviare qualsiasi cosa e prima abbiamo chiamato accept. Naturalmente, la gestione di questo caso dipende dal sistema operativo, ma è possibile che accept bloccherà semplicemente fino a quando non verrà stabilita una nuova connessione, il che farà sì che la nostra applicazione attenda per un tempo indefinito impedendo l'elaborazione di altri socket. Se la tua presa di ascolto è in modalità non bloccante, ciò non accadrà e otterrai EWOULDBLOCK o qualche altro errore, ma il accept non verrà bloccato.

Alcuni kernel avevano (spero sia stato risolto) un bug interessante con UDP e select. Quando arriva un datagramma select si sveglia con il socket con datagramma contrassegnato come pronto per la lettura. La convalida del checksum del datagramma viene posticipata fino a quando un codice utente non chiama recvfrom (o qualche altra API in grado di ricevere datagrammi UDP). Quando il codice chiama e il codice di convalida rileva una mancata corrispondenza di checksum, un datagramma viene semplicemente eliminato e viene bloccato fino all'arrivo di un prossimo datagramma. Una delle patch che risolve questo problema (insieme alla descrizione del problema) può essere trovata here.

2

Uno dei vantaggi consiste nel rilevare eventuali errori di programmazione, perché se si tenta di leggere un socket che normalmente blocca l'utente, si otterrà invece EWOULDBLOCK. Per oggetti diversi da socket, il comportamento esatto di api potrebbe cambiare, vedere http://www.scottklement.com/rpg/socktut/nonblocking.html.

+0

Aha, grazie per quello. :) – CaptainCodeman

1

Questo suono sembrerà snarky ma non lo è. Il miglior motivo per renderli non bloccanti è che non blocchi.

Pensaci. select() ti dice che c'è qualcosa da leggere ma non sai quanto. Potrebbe essere 2 byte, potrebbe essere 2.000. Nella maggior parte dei casi è più efficiente scaricare tutti i dati presenti prima di tornare a select. Quindi entri in un ciclo while per leggere

while (1) 
{ 
    n = read(sock, buffer, 200); 
    //check return code, etc 
} 

Cosa succede nell'ultima lettura quando non c'è più niente da leggere? Se il socket non è non bloccante, bloccherai, sconfiggendo (almeno parzialmente) il punto dello select().

3

Oltre ai bug del kernel menzionati da altri, un altro motivo per scegliere socket non bloccanti, anche con un ciclo di polling, è che consente prestazioni più elevate con dati in arrivo. Pensa cosa succede quando un socket di blocco è contrassegnato come "leggibile". Non hai idea di quanti dati siano arrivati, così puoi leggerlo tranquillamente solo una volta.Quindi è necessario tornare al ciclo degli eventi per fare in modo che il poller verifichi se il socket è ancora leggibile. Ciò significa che per ogni singola lettura o scrittura sul socket devi fare almeno due chiamate di sistema: il select per dirti che è sicuro da leggere e la chiamata di lettura/scrittura stessa.

Con socket non bloccanti è possibile saltare le chiamate non necessarie a select dopo il primo. Quando un socket è contrassegnato come leggibile da select, hai la possibilità di leggerlo da esso fino a quando restituisce i dati, il che consente un'elaborazione più veloce di rapide sequenze di dati.

+0

Grazie, ottimo punto, non sapevo che provare a leggere sarebbe stato più veloce di un altro selezionare. – CaptainCodeman

Problemi correlati