2009-04-09 3 views
3

Ist dies der richtige Weg, um über eine read auf einem Sockel zu iterieren? Es fällt mir schwer, das richtig zu machen. data.size ist ein unsigned int, der ebenfalls aus dem Socket geladen wird. Das ist richtig. data.data ist ein unsigned char *.Iterieren eines Lese() aus einem Socket

if (data.size > 0) { 
    data.data = (unsigned char*)malloc(data.size); 
    memset(&data.data, 0, data.size); 
    int remainingSize = data.size; 
    unsigned char *iter = data.data; 
    int count = 0; 
    do { 
     count = read(connect_fd, iter, remainingSize); 
     iter += count; 
     remainingSize -= count; 
    } while (count > 0 && remainingSize > 0); 
} 
else { 
    data.data = 0; 
} 

Vielen Dank im Voraus.

Antwort

9

Sie müssen den Rückgabewert überprüfen, bevor Sie ihn anderen Werten hinzufügen.

Sie erhalten eine Null, wenn der Socket EOF meldet, und -1 bei Fehler. Beachten Sie, dass für einen Socket EOF nicht dasselbe ist wie geschlossen.

3

Setzen Sie die Lese als Teil der während Bedingung zu lesen.

while((remainingSize > 0) && (count = read(connect_fd, iter, remainingSize)) > 0) 
{ 
    iter += count; 
    remainingSize -= count; 
} 

Auf diese Weise stoppen Sie die Schleife sofort, wenn es fehlschlägt.
Es ist sehr üblich, das Lesen als Teil der Schleifenbedingung zu verwenden, andernfalls müssen Sie den Zustand innerhalb der Schleife überprüfen, der den Code hässlicher macht.

Persönlich:
Ich würde den ganzen obigen Test in eine getrennte Funktion für die Lesbarkeit verschieben, aber Ihre Milage kann sehr.

Auch mit malloc (und Unternehmen) wird zu einem ganzen Boot der Speicherverwaltung Probleme führen. Ich würde einen Std :: Vektor verwenden. Dies schützt auch den Code, wenn Sie ihn modifizieren, um mit dem Auslösen von Ausnahmen zu beginnen, jetzt wird er auch ausnahmesicher sein.

So vorausgesetzt, Sie data.data eine Art von std haben ändern :: vector < unsigned char > dann

if (data.size > 0) 
{ 
    std::vector<unsigned char> buffer(data.size); 

    unsigned char *iter = &buffer[0]; 
    while(... read(connect_fd, iter, remainingSize)) 
    { 
     ..... 
    } 

    ... handle error as required 

    buffer.resize(buffer.size() - remainingSize); 
    data.data.swap(buffer); 
} 
3

Beachten Sie, dass() Anrufe sind Systemaufrufe und damit eine Quelle möglicher Sperr lesen und selbst wenn Sie nicht blockierende E/A verwenden, sind sie von Natur aus schwergewichtig. Ich würde empfehlen, sie zu minimieren.

Ein guter Weg zu gehen, der mir immer gut in mehr als einem Jahrzehnt der BSD-Socket-Programmierung in C gedient hat, ist die Verwendung nicht blockierender I/O und Ausgabe eines FIONREAD ioctl(), um die Gesamtmenge an Daten zu erhalten ein bestimmtes Abfrageintervall (vorausgesetzt, Sie verwenden eine Art von synchronem I/O-Mux wie select()) und lesen Sie dann() so oft wie nötig, um alles zu erfassen, und geben Sie dann die Funktion für den Moment zurück bis zum nächsten Timer Tick.

Verwandte Themen