M. J. J.: C: Dateiendekennung fehlt?!

Hallo,

nun ich will euch zunächst mal ein wenig C-Code zeigen.

  
// socket(), bind(), listen(), accept()  
// Dann kommt folgender Code  
char buf[512] = {0};  
char* r = NULL;  
FILE* fd  = fdopen(socket, "r"); // socket stammt von accept()  
printf("feof(): %d\n", feof(fd));  
while(feof(fd) != EOF) {  
 r = fgets(buf, sizeof(buf), fd);  
 if(r != 0 && r != '\0') {  
  printf("%s", r);  
 } else {  
  break;  
 }  
}  

Also ich programmiere unter GNU/Linux, so vorweg mal.
Das ganze soll ein TCP/IP Server für die Schule werden.

Ausgabe:
feof(): 0 // Zitat aus man feof "feof liefert ein Ergebnis ungleich 0, wenn die Dateiendekennung gesetzt ist."
// Was wiederum meine Erklärung für das Verhalten unten ist.
GET / HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.5) Gecko/20070718 Fedora/2.0.0.5-1.fc7 Firefox/2.0.0.5
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cache-Control: max-age=0
// Hier wartet der Server in der while-Schleife auf Nahrung in Byteform, weil er die Dateiendekennung die hier sein sollte nicht findet

Wie kann sowas sein und wie kann ich es (mein Problem) lösen?

Ich hoffe ich konnte mein Problem verständlich und prägnant erläutern.

Grüße,
M. J. J.

  1. Ahoi M. J. J.,

    ich kenn mich mit C nid aus, aber lass dir doch mal socket ausgeben.
    denn dort scheint wohl die dateiendung zu fehlen.

    MfG

  2. Hi,

    Hallo,

    nun ich will euch zunächst mal ein wenig C-Code zeigen.

    // socket(), bind(), listen(), accept()
    // Dann kommt folgender Code
    char buf[512] = {0};
    char* r = NULL;
    FILE* fd  = fdopen(socket, "r"); // socket stammt von accept()
    printf("feof(): %d\n", feof(fd));
    while(feof(fd) != EOF) {
    r = fgets(buf, sizeof(buf), fd);
    if(r != 0 && r != '\0') {
      printf("%s", r);
    } else {
      break;
    }
    }

    
    >   
      
    
    > Wie kann sowas sein und wie kann ich es (mein Problem) lösen?  
      
    Ich hoffe ich kann dir helfen, auch wenn ich den Unterschied zwischen Socket und File nicht kenne.  
    In deiner if-Abfrage steht erst "r != 0". r ist ein Pointer, wenndann hat er den Wert NULL.  
    Danach kommt "r != '\0'". Hier vergleichst du eine Adresse (Wert des Pointers mit '\0'. Was willst du damit erreichen?  
      
    Hier noch eine Beschreibung zum Rueckgabewert von fgets():  
    Zeiger auf den eingelesenen Zeichenvektor oder NULL bei Dateiende oder einem Fehler.  
      
    mfG,  
    steckl
    
  3. Yerf!

    while(feof(fd) != EOF) {

    feof(): 0 // Zitat aus man feof "feof liefert ein Ergebnis ungleich 0, wenn die Dateiendekennung gesetzt ist."

    Was mir hier auffällt: EOF ist eine Konstante für die EOF-Markierung, um diese direkt Abfragen zu können (weis jetzt nicht den genauen Wert).

    Müsste das nicht while(feof(fd) == 0) heißen?

    Gruß,

    Harlequin

    1. Hallo,

      while(feof(fd) != EOF) {

      diese Stelle fiel mir auch auf.

      Müsste das nicht while(feof(fd) == 0) heißen?

      Ja, oder gebräuchlicher und "lesbarer":
       while (!feof(fd))
      Lies: "Solange nicht Dateiende von fd" ...

      So long,
       Martin

      --
      Wer schläft, sündigt nicht.
      Wer vorher sündigt, schläft besser.
  4. Ich habe den Code nun so abgeändert:

      
    char buf[512] = {0};  
    char* r = NULL;  
    FILE* fd  = fdopen(socket, "r");  
      
    printf("Request: \n");  
      
    while(!feof(fd)) {  
     r = fgets(buf, sizeof(buf), fd);  
     printf("%s", r);  
    }  
      
    printf("hallo");  
    
    

    Aber das Programm 'hängt' immer noch an/in der Schleife fest.
    Das printf nach der Schleife wird erst ausgegeben wenn der Client die Verbindung beendet. Aber es sollte ausgegeben werden wenn die Anfrage zuende ist und ich bin immer noch der Meinung das die Dateiendekennung fehlt.
    Was tun?

    1. Ahoi M. J. J.,

      Was tun?

      Gib socket aus, dann weisst du ob die Dateiendung fehlt oder nicht.

      MfG

    2. Hallo,

      char buf[512] = {0};

      char* r = NULL;
      FILE* fd  = fdopen(socket, "r");

      printf("Request: \n");

      while(!feof(fd)) {
      r = fgets(buf, sizeof(buf), fd);
      printf("%s", r);
      }

      printf("hallo");

        
      sieht okay aus - abgesehen davon, dass r überflüssig ist und du ebensogut buf ausgeben könntest (fgets gibt als Ergebnis den Zeiger auf den Puffer zurück, oder NULL im Fehlerfall).  
        
      
      > Das printf nach der Schleife wird erst ausgegeben wenn der Client die Verbindung beendet.  
        
      Ja, selbstverständlich. Erst wenn der sendende Teilnehmer die Verbindung beendet, kann der empfangende Teilnehmer auf Socket-Ebene erkennen, dass das Ende der Daten bzw. das Ende der Übertragung erreicht ist (oder eben durch ein Timeout).  
        
      
      > Aber es sollte ausgegeben werden wenn die Anfrage zuende ist ...  
        
      Woran würde man das erkennen, wie würde man dieses Ende definieren? Falls die Information über das Ende in den Nutzdaten steckt, müsstest du das auch auf der Ebene abfrühstücken. Das heißt, du musst beim Empfang schon die Daten analysieren und auf "logischer Ebene" eine Endekennung realisieren.  
        
      Auf Socket-Ebene ist das Abbauen der Verbindung das einzige Merkmal, an dem der horchende Teilnehmer das Ende der Übertragung erkennen kann, so dass feof() überhaupt anspricht. Anders gesagt: foef() kann aufgrund seiner Implementierung nur verbindungsorientiert das Ende anzeigen. Solange die Verbindung bestehen bleibt, ist feof() machtlos und das falsche Werkzeug - der sendende Teilnehmer könnte ja jederzeit nochmal Daten nachlegen.  
        
      
      > und ich bin immer noch der Meinung das die Dateiendekennung fehlt.  
        
      Wie würde die deiner Meinung nach aussehen?  
        
      So long,  
       Martin  
      
      -- 
      Nicht jeder, der aus dem Rahmen fällt, war vorher im Bilde.
      
      1. Woran würde man das erkennen, wie würde man dieses Ende definieren? Falls die Information über das Ende in den Nutzdaten steckt, müsstest du das auch auf der Ebene abfrühstücken. Das heißt, du musst beim Empfang schon die Daten analysieren und auf "logischer Ebene" eine Endekennung realisieren.

        Nehmen wir mal als Beispiel Protokol HTTP.
        Bei GET-Requests ist \r\n\r\n das Ende.
        Bei POST-Anfragen gibt es im Header Content-length: x
        Da muss man x Zeichen nach dem Header lesen.
        Aber mal angenommen jemand schickt mir ein Request die so aussieht:
        POST / HTTP/1.1\r\n
        Content-length: 5\r\n
        ... ...\r\n\r\n
        f=34

        Folge ist das ein Zeichen laut Headerinformation fehlt. Also warte ich auf das Zeichen. Aber es kommt hald keins.
        Soll ich dann eine solche Anfrage verwerfen?
        Und das Warten soll dann durch ein Timeout abgebrochen werden?
        Das wäre soweit ja ok.

        Aber gibt es wirklich keine andere Möglichkeit ein Ende in so einem Stream zu finden? (Dateiendekennung?!)

        M. J. J.

        1. Hallo,

          Nehmen wir mal als Beispiel Protokol HTTP.
          Bei GET-Requests ist \r\n\r\n das Ende.
          Bei POST-Anfragen gibt es im Header Content-length: x
          Da muss man x Zeichen nach dem Header lesen.

          ja, und wenn für x ein falscher Wert übermittelt wird, kommt sich der Kommunikationspartner mächtig verarscht vor. ;-)

          POST / HTTP/1.1\r\n
          Content-length: 5\r\n
          ... ...\r\n\r\n
          f=34

          Folge ist das ein Zeichen laut Headerinformation fehlt. Also warte ich auf das Zeichen. Aber es kommt hald keins.
          Soll ich dann eine solche Anfrage verwerfen?

          Nach "angemessener" Wartezeit, ja.
          Das Problem tritt eigentlich bei allen Übertragungen auf, bei denen Zeichen sequentiell übermittelt werden, aber logische Blöcke bilden. Hast du schon einmal eine Kommunikation mit irgendeinem Gerät über die COM-Schnittstelle programmiert? Da kann dich so ein Problem genauso treffen. Beispielsweise verlangt das Protokoll, dass Anfragen immer mit einem \r enden, du bekommst aber nur ein paar druckbare Zeichen und dann lange Zeit nichts.
          Du hast in so einem Fall keine andere Chance, als nach einer definierten Wartezeit die Anfrage zu verwerfen - entweder still ignorieren, oder eine Fehlermeldung ausgeben, oder dem Kommunikationspartner signalisieren, "Spiel's noch einmal, Sam".

          Und das Warten soll dann durch ein Timeout abgebrochen werden?
          Das wäre soweit ja ok.

          Genau. Ist zwar ein bissl Programmieraufwand, muss aber sein, wenn das System einigermaßen stabil funktionieren soll.

          Aber gibt es wirklich keine andere Möglichkeit ein Ende in so einem Stream zu finden? (Dateiendekennung?!)

          Nein. Das ist eben etwas anderes, als wirklich eine Datei zu lesen, deren Länge das Betriebssystem genau kennt.

          Ciao,
           Martin

          --
          Most experts agree: Any feature of a program that you can't turn off if you want to, is a bug.
          Except with Microsoft, where it is just the other way round.
          1. Martin, du hast mir wirklich sehr geholfen. Vielen Dank!

            Grüße,

            M. J. J.