2017-01-12 1 views
1

Ich versuche, Integer-Wert in/aus C-Buchse zu schreiben und zu lesen. Manchmal gibt ntohs() sehr große Werte wie 55000, 32000 usw. zurück. Obwohl Client immer Wert < 1500 sendet. Wenn ich das Programm laufe, passiert es nach 10-15 Minuten ... Manchmal nach 20-30 Minuten.ntohs() Problem: Schreibe Integer in C-Socket

Können Sie bitte unten Code überprüfen und mir sagen Warum diese Zeile gedruckt wird?

printf ("Müllwert - ntohs Problem .. Beenden ...");

// write exactly n byte 
inline int write_n(int fd, char *buf, int n) { 

    int nwrite, left = n; 
    int totalwrite = 0; 

    while (totalwrite != n) { 
     if ((nwrite = write(fd, buf, left)) <= 0) { 
      break; 
     } else { 
      totalwrite = totalwrite + nwrite; 
      left -= nwrite; 
      buf += nwrite; 
     } 

    } 
    if (totalwrite == 0) 
     return nwrite; 
    return totalwrite; 
} 

// send exactly n byte 
inline int send_n(int fd, char *buf, int n) { 

    int nwrite, left = n; 
    int totalwrite = 0; 

    while (totalwrite != n) { 
     if ((nwrite = send(fd, buf, left, MSG_NOSIGNAL)) <= 0) { 
      break; 
     } else { 
      totalwrite = totalwrite + nwrite; 
      left -= nwrite; 
      buf += nwrite; 
     } 

    } 
    if (totalwrite == 0) 
     return nwrite; 

    return totalwrite; 
} 



uint16_t nread, len, plength, nsend; 
int MTU = 1500; 
char buffer[2000]; 

// Server receive (Linux 64 bit) 
while (1) { 
    // read packet length 
    nread = read_n(TCP_SOCKFD, (char *) &plength, sizeof(plength)); 
    if (nread <=0) { 
     break; 
    } 

    len = ntohs(plength); 
    if (len <=0 || len > 1500) { 
     **printf("Garbage value - ntohs problem ..Exiting... "); // WHY ?** 
     break; 
    } 

    // read packat data 
    nread = read_n(SOCKFD, buffer, len); 
    if (nread != len) { 
     break; 
    } 

} 

//--------------------- 
// CLIENT send (Android 5) 
while (1) { 

    nread = read(tunfd, buffer, MTU); 

    if (nread <= 0 || nread > 1500) { // always <=1500 
     break; 
    } 

    plength = htons(nread); 
    // send packet lenght 
    nsend = send_n(TCP_SOCKFD, (char *) &plength, sizeof(plength)); 
    if (nsend != sizeof(plength)) { 
     break; 
    } 
    // send packet data 
    nsend = send_n(TCP_SOCKFD, buffer, nread); 
    if (nsend != nread) { 
     break; 
    } 

} 

Danke

+0

Sie sicher, dass es nicht das Drucken wenn/wenn 'len == 0'? Auch 'len' ist ein' uint16_t', es sollte nicht kleiner als 0 sein. Sicherlich gibt es dort Compilerwarnungen. – yano

+1

1) Betrachten Sie die Deklaration/Definition von 'read_n()'.2) Ich würde 'nread = read_n (TCP_SOCKFD, (char *) & plength, sizeof (plength)) erwarten; if (nread chux

+1

'printf (" Müllwert% X - ntohs Problem .. Beenden ... ", 1u * len)' wäre informativer. – chux

Antwort

2

wir Sie nicht mit Sicherheit sagen kann, was passiert, weil Sie nicht nachprüfbare Beispiel bieten kann. Darüber hinaus haben Sie die Implementierung von read_n() nicht vorgestellt, aber unter der Annahme, dass es dem gleichen Modell wie write_n() und send_n() folgt, können wir dennoch einige Analysen durchführen.

Jede der Datenübertragungsfunktionen gibt eine kurze Zählung zurück, wenn die Datenübertragung durch einen Fehler unterbrochen wird. Der Client-Code überwacht dies und bricht aus seiner Schleife, wenn er es erkennt. Schön und gut. Der Servercode tut dies jedoch nicht beim Lesen plength. Da plength als uint16_t zwei Byte groß ist, ist ein partielles Lesen möglich und würde von Ihrem Servercode nicht bemerkt.

In Ihrem Beispiel wird plength nur über den einen read_n() Aufruf geändert, der dargestellt wird. Netzwerk-Byte-Reihenfolge ist Big-Endian, so dass das höchstwertige Byte zuerst gelesen wird. Es ist möglich, dass die Kombination dieses Bytes mit dem veralteten vom vorherigen gelesenen eine Zahl darstellen würde, die 1500 übersteigt. Zum Beispiel, wenn auf ein 221 (0x00dd) -Byte-Paket ein 1280 (0x0500) -Byte-Paket folgt, und ein partielles Lesen tritt bei der zweiten Paketgröße auf, dann ist das kombinierte Ergebnis 1501 (0x05dd).

Ich sehe derzeit keinen Grund zu der Annahme, dass der Client Daten anders sendet, als Sie denken, und ich sehe derzeit keine andere Möglichkeit, dass Ihr Servercode den Anschein erwecken könnte, andere Daten zu empfangen als der Client sendet, zumal Client und Server jeweils beim ersten erkannten Störungszeichen abbrechen.

Beachten Sie jedoch, dass dieser Code noch robuster sein könnte. Beachten Sie insbesondere, dass read(), write() und send() auch dann fehlschlagen können, wenn kein Problem mit der zugrunde liegenden Socket- oder Datenübertragungsanforderung vorliegt. Insbesondere können sie mit EINTR fehlschlagen, wenn der Anruf durch ein Signal unterbrochen wird, und wenn sich der Socket im nicht blockierenden Modus befindet, können sie mit EAGAIN fehlschlagen. Es könnte andere geben. Es scheint nicht sinnvoll zu sein, Ihren Socket im nicht-blockierenden Modus zu betreiben, aber Sie möchten vielleicht nach EINTR Ausschau halten und das Lesen nach dem Empfang fortsetzen.

Ich würde auch vorschlagen, dass Sie zumindest während der Entwicklung mehr Daten über die Art des Fehlers ausstrahlen. Rufen Sie beispielsweise perror() an und drucken Sie anschließend die fehlerhaften Daten aus. Sie könnten sogar erwägen, gesendete und empfangene Daten zu protokollieren.

+0

Danke. Wie Sie vorgeschlagen haben, habe ich festgestellt, dass beim unerwarteten Abbruch der Verbindung partielle Daten gelesen werden. Also wird der Wert des Müllwertes von ntohs zurückgegeben. So können wir das Ende der Verbindung betrachten. Vielen Dank – NetTech