Perché la chiamata di sistema recv
non viene bloccata finché tutti i dati non vengono ricevuti? Ogni volta che ho visto una chiamata recv
, è in un ciclo while che continua a chiamare recv
fino a quando tutti i dati sono lì. Perché non solo avere il blocco recv
in primo luogo?Perché non si ripristina il blocco finché non riceve tutti i dati?
risposta
È possibile richiedere il blocco di recv finché tutti i dati non vengono ricevuti, con il flag MSG_WAITALL
. Tuttavia, se arriva un segnale, una chiamata di sistema che ha eseguito un po 'di lavoro (ad esempio, la ricezione di parte dei dati) non può essere riavviata automaticamente per ricevere il resto. Pertanto, anche con MSG_WAITALL
, ci sono casi in cui la chiamata recv può tornare prima che il buffer sia pieno, e si deve essere pronti a gestire questi casi. Detto questo, molte persone scelgono semplicemente di eseguire il ciclo e di non disturbare con i flag poco noti come MSG_WAITALL
.
Per quanto riguarda il motivo per cui questo è il caso di default, ci sono alcuni motivi che vengono in mente:
- Spesso si vogliono per ricevere letture parziali. Ad esempio, se stai visualizzando in modo incrementale i dati mentre vengono ricevuti, o se stai trasmettendo il proxy da qualche altra parte, o se i dati sono così grandi, non puoi memorizzare l'intero contenuto nella memoria in una sola volta. Dopotutto, se stai scrivendo immediatamente su un file, ti preoccupi di dividerlo su 200 scritture anziché, ad esempio, 150?
- A volte non sai nemmeno quanti dati hai bisogno all'inizio. Si consideri il protocollo
telnet
, che era popolare nel periodo in cui è stata progettata l'API BSD socket. Generalmente riceverai una manciata di byte alla volta, non ci sono campi di lunghezza che ti dicono quanti dati aspettarti e inoltre devi visualizzare immediatamente i dati . Non ha senso bloccare fino a riempire un buffer qui. Allo stesso modo con i protocolli orientati alla linea come SMTP o IMAP, non si sa per quanto tempo il comando è attivo finché non lo si riceve interamente. recv
viene spesso utilizzato per i socket di datagramma, dove riceve un singolo datagramma, anche se è molto più piccolo del buffer fornito. L'estensione naturale alle prese di streaming è di tornare il più possibile senza aspettare.
Ma la cosa più importante, in quanto è necessario essere preparati ad affrontare un buffer parziale comunque, è bene forzare la gente a trattare il caso di default, in modo da alzare gli insetti nel loro ciclo presto - piuttosto che tenerli nascosti finché un segnale non arriva in un momento sfortunato.
Nella maggior parte dei casi, non si conosce la quantità di dati "tutti i dati". Ad esempio, se si ricevono dati in un protocollo orientato alla linea, una linea potrebbe essere lunga 10 byte o lunga 65 byte.
È possibile modificare i flag dei socket su blocco o non blocco. Il tuo caso specifico in realtà non ha nulla a che fare con il blocco o il non blocco.
Non avrebbe senso fare in modo che una funzione di rete si comporti nel modo in cui si descrive per impostazione predefinita - cosa succede se il flusso non termina mai .. il programma non dovrebbe mai terminare? Prima facia, questo non sembra un comportamento corretto predefinito.
Leggere http://www.scottklement.com/rpg/socktut/nonblocking.html per familiarizzare con IO di blocco e non blocco.