2010-11-22 9 views
2

Ich habe die folgende Funktion einrichten, um die Daten vom Server alle 2 Minuten zu erhalten. Zum ersten Mal rufe ich die Funktion an, die es zu funktionieren scheint, aber dann friert es bei dem recv-Aufruf ein, der nie zurückkehrt. und müsste ich den Puffer bei jedem Anruf zuweisen, selbst wenn der Server nichts zu senden hat?Recv eingehenden Datenverkehr vom Server

#define RCVBUFSIZE 32 

void Receive() 
{ 
    UINT totalBytesRcvd = 0, bytesRcvd = 0; 
    char buffer[RCVBUFSIZE];  /* Buffer for string */ 

    /* Receive up to the buffer size (minus 1 to leave space for 
    a null terminator) bytes from the sender */ 

    bytesRcvd = recv(sockClient, buffer, RCVBUFSIZE - 1, 0); 

    if (bytesRcvd) 
    { 
     buffer[bytesRcvd] = '\0'; 
     MessageBox(0, buffer, 0, 0); //some way to display the received buffer 
    } 
    else if (bytesRcvd == SOCKET_ERROR) 
    { 
     return; 
    } 
} 
+2

Hinweis: Ihre 'if (bytesRcvd)' Prüfung erfüllt die 'SOCKET_ERROR' Zustand (die -1), was bedeutet, Sie werden versuchen, schreiben Sie an‚Puffer [-1] ', wenn es einen Fehler und Anschließend geht es weiter in das Bollock-Land! –

Antwort

5

(1) Ihr Puffer ist nicht wirklich zugeordnet, er befindet sich auf dem Stapel. Normalerweise müssen Sie sich keine Gedanken über die Verwendung von 32 Bytes auf dem Stack machen.

(2) recv soll blockieren, bis es etwas zu empfangen hat. Sie können das umgehen, indem Sie nicht blockierende Sockets verwenden oder select verwenden. Bitte beachten Sie here als Referenz.

Insbesondere Sie

(2a) kann ioctlsocket Verwenden Sie Ihre Socket nicht blockierenden Modus einzustellen. Dann, wenn Sie read aufrufen und nichts zu lesen ist, erhalten Sie den Fehler .

unsigned long non_blocking = 1; 
ioctlsocket (sockClient, FIONBIO, &non_blocking); 

Dann wird das Lesen

bytesRcvd = recv(sockClient, buffer, RCVBUFSIZE - 1, 0); 
if (bytesRcvd == -1) { 
    if (WSAGetLastError() == EWOULDBLOCK) { 
     // nothing to read now 
    } else { 
     // an actual error occurred 
    } 
} else { 
    // reading was successful. Call to MsgBox here 
} 

(2b) Oder Sie können select bestimmen nennen, ob Daten zu lesen, bevor sie tatsächlich read aufrufen.

struct timeval timeout; 
timeout.tv_usec = 0; 
timeout.tv_sec = 0; 

fd_set r; 
FD_ZERO (&r); 
FD_SET (sockClient, &r); 
switch (select (sockClient + 1, &r, NULL, NULL, &timeout)) { 
    case -1: 
     // error 
     break; 
    case 0: 
     // nothing to read 
     break; 
    case 1: 
     // you may call read() 
     break; 
} 
+1

+1, gute Antwort. Es ist auch erwähnenswert, dass Sie 'MSG_PEEK' an recv() übergeben können, um zu prüfen, ob irgendwelche Bytes zum Lesen verfügbar sind. –

+0

Wenn ich mit (2b) gehen würde, dann müssen Sie keinen Puffer beliebiger Größe im Stapel vorbelegen oder deklarieren. aber lohnt es sich immer noch, den Sockel als nicht blockierend mit FIONBIO zu markieren? – cnd

+0

Wenn Sie keine Multithread-Einstellungen haben (* und * einen schwerwiegenden Fehler haben), oder die Einstellung von 'FIONBIO' nicht vornehmen, sollte bei der Verwendung von' Select'-basiertem Multiplexing kein Unterschied gemacht werden. – dennycrane