tutorials.de Buch-Aktion 05/2012
Seite 1 von 2 12 LetzteLetzte
ERLEDIGT
NEIN
ANTWORTEN
22
ZUGRIFFE
939
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    huebstAr huebstAr ist offline Mitglied
    Registriert seit
    Jun 2009
    Beiträge
    13
    Hi an Alle!

    Wie im Topic zu lesen soll dieses Programm einen kleinen Webserver darstellen, der zunächst einmal nur die Seite bei einem Request in den Socket zurückschreiben soll.

    Leider scheint hier irgendwo ein Fehler zu sein, da ich, wenn ich die Seite 127.0.0.1 aufrufe, eine Fehlermeldung im Browser bekomme.

    Ich stehe nur etwas auf dem Schlauch, da die Kontrollausgaben im Programm so aussehen, wie ich sie mir vorgestellt habe.

    Wisst ihr vielleicht weiter?

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    
    //
    // Programm:         einfacher Webserver
    // Funktiosumfang:    Lauschen auf Port 80, bei Anfrage einer Seite,
    //            diese zum anfragenden Client zurücksenden
     
     
    //----------------------------------------------------------------------------
    // Einbinden der Headerdateien
    #include <sys/types.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <errno.h>
     
    // Prototypen der verwendeten Funktionen
    int deploy_server();
    void process_request(int result_accept);
     
    int main()
    {
        int     sock=-1,
            source=0,
            result_accept=0,
            pid=-1,
            len_addr=0,
            status=0;
        struct sockaddr_in requestor;
       
        printf(".\n");
        printf(".\n");   
        printf("Webserver v1.0 gestartet\n");
        printf(".\n");
        printf(".\n");
     
        do {
     
            sock = deploy_server();
            if(sock<0)
            {       
                printf("Fehler beim Deployen des Servers!\n");
                printf("<RETURN> für Neuversuch\n\n");
                getchar();
            }
     
        }while(sock < 0);
     
        while(1)
        {
            len_addr = sizeof(source);
            result_accept = accept(sock, (struct sockaddr*) &source, &len_addr);
           
            if(-1 == result_accept)
            {
                printf("Fehler beim Verbindungsaufbau\n");
            }
            else
            {
                printf("Verbindungsaufbau erfolgreich\n");
            }
     
            pid = fork();
           
            if(-1 == pid)
            {   
                printf("Fehler beim erstellen des Sohnprozesses!\n");
            }
           
            if(0 == pid)
            {
                process_request(result_accept);
                exit(0);
                waitpid(-1, &status, WNOHANG);
                printf("Status: %d", status);
            }
           
            close(result_accept);
     
        }
     
    }
     
    int deploy_server()       
    {
        int     sock,
            result_bind=5;
        struct     sockaddr_in adressinfo;
     
        sock = socket(AF_INET, SOCK_STREAM, 0);
       
        bzero(&adressinfo, sizeof(adressinfo));
       
        adressinfo.sin_family = AF_INET;
        adressinfo.sin_port = htons(80);
        adressinfo.sin_addr.s_addr = INADDR_ANY;
       
        result_bind = bind(sock, (struct sockaddr*) &adressinfo, sizeof(adressinfo));
     
        if(result_bind == -1)
        {   
            printf("Fehler bei Bind");
            return -1;   
        }
     
        listen(sock, 2);
        return(sock);
    }
     
    void process_request(int sock)
    {
        char        sendbuffer[8096],
                request[8096],
            filename[8096],
                buffer;
        int     i=0,
                k=0,f=0,
                ext_laenge=0,
                anzahl=0,
                file_descript=0;
        char        get_ext[4];
       
            bzero(&request, sizeof(request));
        bzero(&filename, sizeof(filename));
       
        while(i < sizeof(request)-1)    // solange die Länge des Strings nicht überschritten wird
        {
            if(    read(sock, &buffer, 1) > 0    // Solange ein Zeichen gelesen werden kann
                && buffer != '\n'         // UND kein Zeilenumbruch
                && buffer != '\r')
            {       
                request[i] = buffer;        // weiter einlesen
                i++;
            }
            else
            {
                request[i] = '\0';        // Sonst String abschließen
                break;                // und Schleife abbrechen
            }
        }
     
        // Kontrollausgabe der Anfrage
        for(k=0; k< sizeof(request); k++)
            printf("%c", request[k]);
        printf("\n\n");
       
        // Prüfen ob Get-Anfrage (nicht Case-Sensitive)
        if(!strncmp(request, "GET ", 4) || !strncmp(request, "get ", 4)) // falls GET
        {   
            i=5;                            // Startwert des Index, GET wird ignoriert
       
            if(!strncmp(&request[5], " ", 1))           // Wenn keine Seite angegeben
            {     
                    strcpy(request, "GET /index.html");     // String auf index.html setzen                              
            }
           
        while(strncmp(&request[i], " ", 1) != 0)    // SOLANGE KEIN Leerzeichen gefunden
        {      
            strncpy(&filename[f], &request[i], 1);  // Zeichen an Filename anhängen
            f++; i++;
        }
     
            // Extensions prüfen
            // FEHLT NOCH
            // FEHLT NOCH
            // FEHLT NOCH
            // FEHLT NOCH
       
        printf("OPENING: >%s<\n", filename);
        file_descript=open(filename, O_RDONLY);     // Angefordertes File öffnen
            
        if(file_descript != -1)
            {
             /*     while(anzahl=read(file_descript, sendbuffer, sizeof(sendbuffer)))
                        write(sock, sendbuffer, anzahl);*/
            write(sock, sendbuffer, read(file_descript, sendbuffer, sizeof(sendbuffer)));
                close(file_descript);
            }       
            else
                printf("Fehler! File konnte nicht geöffnet werden!\n");
       
            close(sock);   
        printf("--> ENDE \n");
        }
        else
            printf("Nur GET-Anfragen werden bearbeitet!\n");
    }

    Desweiteren bin ich mir nicht ganz sicher, ob die Anweisung close(sock); (*in Zeile 185) hier an der richtigen Stelle steht, da dort der socket ja eignetlich immer offen gehalten werden sollte?!

    Wo kann ich sie sonst unterbringen? Das Programm wird auf einem SuSe-System ausgefürt und mit Strg+C terminiert. Ich habe die Vermutung, dass hier eventuell der Fehler steckt, da nach einiger Zeit der Aufruf zunächst funktioniert (Seite wird an Client zurückgegeben) und anschließend für eine längere Zeit nicht mehr.


    Gruß
    huebstAr
     

  2. #2
    Avatar von Bratkartoffel
    Bratkartoffel Bratkartoffel ist offline gebratene Kartoffel
    tutorials.de Premium-User
    Registriert seit
    Jun 2007
    Ort
    Passau (Niederbayern)
    Beiträge
    1.394
    Hi,

    welche Fehlermeldung? Hast du schon mal den Request über telnet abgesetzt und geschaut was wirklich vom Server kommt?

    Welchen Standard folgst du? HTTP/1.0 oder HTTP/1.1?

    Gruß
    BK
    huebstAr bedankt sich. 
    Über eine gute Bewertung freut sich jeder ;)
    Bitte erledigte Threads als "Erledigt" markieren.

    "Though a program be but three lines long, someday it will have to be maintained.''
    -- Geoffrey James, "The Tao of Programming"

  3. #3
    huebstAr huebstAr ist offline Mitglied
    Registriert seit
    Jun 2009
    Beiträge
    13
    Hi!

    Das mit Telnet werde ich gleich mal versuchen.

    Hier zu der Fehlermeldung:
    kleiner Webserver in C-snapshot1.png

    Gruss

    Kleiner Edit: Das Spuckt telnet aus
    kleiner Webserver in C-snapshot3.png

    Wobei "lalelu.txt" der Inhalt von index.html ist.
    Geändert von huebstAr (13.12.11 um 18:01 Uhr)
     

  4. #4
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Hi

    Dein Server schließt nach Übertragung die Socketverbindung von sich aus.
    Diesen Teil sollte der Browser übernehmen.
    Sonst kann es passieren, dass nicht alle Byte ankommen.

    Also nach Übertragung weitere Befehle abwarten.
    Wenn recv mit einem Fehlerreturnwert kommt (macht es bei geschlossener Verbindung),
    dann Ende.

    Gruß
     
    Netiquette (vA §15) und Nutzungsregeln (vA §4.8) einhalten! Programmcode in Codetags/Codeboxen.
    Sehr gute Beiträge bitte Bewerten (Stern darunter oder "Danke").
    "Funktioniert nicht" ist zu ungenau! Code, Fehlermeldungen, Verhalten des Programms, ...?

  5. #5
    huebstAr huebstAr ist offline Mitglied
    Registriert seit
    Jun 2009
    Beiträge
    13
    Hi!

    Also verstehe ich nun richtig: Das close(socket); sollte nicht an dieser Stelle stehen, sondern wenn von dem Browser (Client) eine Fehlermeldung kommt, aufgerufen werden?

    €: Nein, falsch verstanden, ich Denke du meinst das close(result_accept); !?
    Geändert von huebstAr (13.12.11 um 18:16 Uhr)
     

  6. #6
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Beides nur so halb.
    Erstens handelt es sich bei result_accept und sock in process_request
    um den gleichen Socket.

    Dann schließt du (nicht in jedem Fall, aber doch) sock schon in process_request,
    und dann schließt du result_accept nocheinmal.

    Drittens soll das nicht gemacht werden, wenn die Fehlermeldung kommt,
    sondern eben, um diese zu verhindern.


    Der Browser schickt "GET irgendwas".
    Dein Server schickt den Inhalt (wo ist eigentlich der Header ).
    Wenn der Browser alles hat, schließt der die Verbindung.
    Der Server muss warten, ob geschlossen wird oder weitere Befehle kommen.

    Abe wo der Head ist, wäre interessant...
    huebstAr bedankt sich. 
    Netiquette (vA §15) und Nutzungsregeln (vA §4.8) einhalten! Programmcode in Codetags/Codeboxen.
    Sehr gute Beiträge bitte Bewerten (Stern darunter oder "Danke").
    "Funktioniert nicht" ist zu ungenau! Code, Fehlermeldungen, Verhalten des Programms, ...?

  7. #7
    huebstAr huebstAr ist offline Mitglied
    Registriert seit
    Jun 2009
    Beiträge
    13
    Danke erstmal!

    Zitat Zitat von sheel Beitrag anzeigen
    Beides nur so halb.
    Erstens handelt es sich bei result_accept und sock in process_request
    um den gleichen Socket.

    Dann schließt du (nicht in jedem Fall, aber doch) sock schon in process_request,
    und dann schließt du result_accept nocheinmal.
    Leuchtet mir so halb ein. Wenn ich den Socket schon geschlossen habe und dann nochmals schließe (wobei aber noch keine neue Socket-Nr eingetragen wurde), passiert ja im Prinzip nichts, oder?

    Zitat Zitat von sheel Beitrag anzeigen
    Drittens soll das nicht gemacht werden, wenn die Fehlermeldung kommt,
    sondern eben, um diese zu verhindern.
    Hier weiß ich nicht, was du damit meinst. Der Socket soll doch nach jedem mal geschlossen werden, falls eine Seite übertragen wurde. Sofern bin ich mir nun nicht ganz sicher, was du meinst mit "Fehlermeldung verhindern".

    Zitat Zitat von sheel Beitrag anzeigen
    Dein Server schickt den Inhalt (wo ist eigentlich der Header ).
    Wenn der Browser alles hat, schließt der die Verbindung.
    Meinst du den Kopf der HTML-Seite? Habe ich nun nachträglich eingefügt. Das dürfte ja aber nicht zu der nicht-anzeige führen, oder?

    Zitat Zitat von sheel Beitrag anzeigen
    Der Server muss warten, ob geschlossen wird oder weitere Befehle kommen.
    Wie kann ich auf dieses Ereignis warten? Was schickt der Browser denn für eine Stop-Condition? Der Server soll nur eine Seite anzeigen, weiteres nicht.


    Gruß
     

  8. #8
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Zum Schließen: Ob da was passiert oder nicht, ist nicht garantiert.
    Das Programm könnte auch ebensogut abstürzen.

    Mit Header meinte ich den des HTTP-Protokolls...
    hier das Inhaltsverzeichnis

    Genauer das:
    http://www.w3.org/Protocols/rfc2616/...sec4.html#sec4

    Und wie man erkennt, ob die Gegenseite den Socket schließt:
    recv liefert einen Fehlercode.
    read ist sowieso fehl am Platz.
     
    Netiquette (vA §15) und Nutzungsregeln (vA §4.8) einhalten! Programmcode in Codetags/Codeboxen.
    Sehr gute Beiträge bitte Bewerten (Stern darunter oder "Danke").
    "Funktioniert nicht" ist zu ungenau! Code, Fehlermeldungen, Verhalten des Programms, ...?

  9. #9
    Avatar von Bratkartoffel
    Bratkartoffel Bratkartoffel ist offline gebratene Kartoffel
    tutorials.de Premium-User
    Registriert seit
    Jun 2007
    Ort
    Passau (Niederbayern)
    Beiträge
    1.394
    Hi,

    zuerstmal: Es ist egal, ob der Server oder der Client die Verbindung schließt.
    Bei persistenten Verbindungen (ab HTTP/1.1) wird die Verbindung (mit einem richtigen Header) zum Beispiel primär vom Client geschlossen, wenn der nichts mehr zu sagen hat. Bei HTTP/1.0 oder nicht persistenten Verbindungen schließt der Server die Verbindung, sobald er alle Daten gesendet hat. Der entsprechende Header nennt sich "Connection" und hat dann entweder "close" oder "Keep-Alive" als Wert.

    Ich denke mal, dass du das HTTP-Protokoll nicht RFC-konform umsetzt und sich daher der Firefox weigert was anzuzeigen.

    Wie sieht dein Request an den Server und die Antwort darauf exakt aus?
    Es sollte in etwa so aussehen:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    /* REQUEST START */
    GET /index.html HTTP/1.0
    Zusaetzliche-Header: Felder
     
    /* REQUEST ENDE */
    /* ANSWER START */
    HTTP/1.0 200 OK
    Content-Type: text/plain
    Content-Length: 29
     
    dies ist der text der antwort
    /* ANSWER ENDE*/

    Woruaf ich dich besonders hinweisen möchte: Zwischen dem Header und dem Body steht eine Leerzeile (genauso am Ende des Requests) und bei der Antwort muss das Feld "Content-Length" gesetzt sein. Ob der "Content-Type" auch benötigt wird, kann ich dir ausm Gedächtnis leider nicht sagen, würde den aber trotzdem mitsenden.

    Edit: Hier noch ein bisschen was zum Lesen für dich: RFC 2616

    Gruß,
    BK
    Geändert von Bratkartoffel (14.12.11 um 11:01 Uhr)
    sheel und huebstAr bedanken sich. 
    Über eine gute Bewertung freut sich jeder ;)
    Bitte erledigte Threads als "Erledigt" markieren.

    "Though a program be but three lines long, someday it will have to be maintained.''
    -- Geoffrey James, "The Tao of Programming"

  10. #10
    huebstAr huebstAr ist offline Mitglied
    Registriert seit
    Jun 2009
    Beiträge
    13
    Hi!

    Danke erstmal für die Ausführung. Habe nun (erst einmal) den Header so eingefügt. Da ich noch einige kleiner Änderungen durchgeführt habe, schreibe ich hier nochmal den aktuellen Code rein:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    
    //----------------------------------------------------------------------------
    // Einbinden der Headerdateien
    #include <sys/types.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <errno.h>
     
    // Prototypen der verwendeten Funktionen
    int deploy_server();
    void process_request(int result_accept);
     
    int main()
    {
        int     sock=-1,
            source=0,
            result_accept=0,
            pid=-1,
            len_addr=0,
            status=0;
        struct sockaddr_in requestor;
       
        printf(".\n");
        printf(".\n");   
        printf("Webserver v1.0 gestartet\n");
        printf(".\n");
        printf(".\n");
     
        do {
     
            sock = deploy_server();
            if(sock<0)
            {       
                printf("Fehler beim Deployen des Servers!\n");
                printf("<RETURN> für Neuversuch\n\n");
                getchar();
            }
     
        }while(sock < 0);
     
        while(1)
        {
            len_addr = sizeof(source);
            result_accept = accept(sock, (struct sockaddr*) &source, &len_addr);
           
            if(-1 == result_accept)
            {
                printf("Fehler beim Verbindungsaufbau\n");
            }
            else
            {
                printf("Verbindungsaufbau erfolgreich\n");
            }
     
            pid = fork();
           
            if(-1 == pid)
            {   
                printf("Fehler beim erstellen des Sohnprozesses!\n");
            }
           
            if(0 == pid)
            {
                process_request(result_accept);
                exit(0);
                waitpid(-1, &status, WNOHANG);
                printf("Status: %d", status);
            }
           
            close(result_accept);
     
        }
     
    }
     
    int deploy_server()       
    {
        int     sock,
            result_bind=5;
        struct     sockaddr_in adressinfo;
     
        sock = socket(AF_INET, SOCK_STREAM, 0);
       
        bzero(&adressinfo, sizeof(adressinfo));
       
        adressinfo.sin_family = AF_INET;
        adressinfo.sin_port = htons(80);
        adressinfo.sin_addr.s_addr = INADDR_ANY;
       
        result_bind = bind(sock, (struct sockaddr*) &adressinfo, sizeof(adressinfo));
     
        if(result_bind == -1)
        {   
            printf("Fehler bei Bind");
            return -1;   
        }
     
        listen(sock, 5);
        return(sock);
    }
     
    void process_request(int sock)
    {
        char        sendbuffer[8096],
                request[8096],
            filename[8096],
                buffer;
        int     i=0,
                k=0,f=0,
                ext_laenge=0,
                anzahl=0,
                file_descript=0;
        char        ex_extension[4];
       
            bzero(&request, sizeof(request));
        bzero(&filename, sizeof(filename));
        bzero(&sendbuffer, sizeof(sendbuffer));
        bzero(&ex_extension, sizeof(ex_extension));
       
        while(i < sizeof(request)-1)    // solange die Länge des Strings nicht überschritten wird
        {
            if(    read(sock, &buffer, 1) > 0       // Solange ein Zeichen gelesen werden kann
                && buffer != '\n'               // UND kein Zeilenumbruch
                && buffer != '\r')
            {       
                request[i] = buffer;        // weiter einlesen
                i++;
            }
            else
            {
                request[i] = '\0';          // Sonst String abschließen
                break;                  // und Schleife abbrechen
            }
        }
     
        // Kontrollausgabe der Anfrage
        for(k=0; k< sizeof(request); k++)
            printf("%c", request[k]);
        printf("\n\n");
       
        // Prüfen ob Get-Anfrage (nicht Case-Sensitive)
        if(!strncmp(request, "GET ", 4) || !strncmp(request, "get ", 4)) // falls GET
        {   
            i=5;                            // Startwert des Index, GET wird ignoriert
        f=0;
       
            if(!strncmp(&request[5], "\0", 1) || !strncmp(&request[5], "\0", 1))    // Wenn keine Seite angegeben
            {     
            printf("keine page\n");
                    strcpy(request, "get /index.html ");        // String auf index.html setzen                              
            }
           
        while(strncmp(&request[i], " ", 1)) // SOLANGE KEIN Leerzeichen erreicht
        {      
            strncpy(&filename[f], &request[i], 1);  // Zeichen an Filename anhängen
            f++; i++;
        }
     
        i=0;
        
            // Extensions extrahieren
            while(strncmp(&filename[i], ".", 1))        // Punkt suchen
            {     
            i++;
            }
        strcpy(ex_extension, &filename[i+1]);       // Fileextension extrahieren
       
         // Extension zuordnen
         // FEHLT
         // FEHLT
         // FEHLT
          
        printf("OPENING: >%s<\n", filename);
        printf("EXTENSION: >%s<\n", ex_extension);
        file_descript=open(filename, O_RDONLY);     // Angefordertes File öffnen
            
        if(file_descript != -1)
            {
            sprintf(request, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
            anzahl=read(file_descript, sendbuffer, sizeof(sendbuffer));
            {
            write(sock, sendbuffer, anzahl);
            }
            
            close(file_descript);
            }       
            else
                printf("Fehler! File konnte nicht geöffnet werden!\n");
       
        printf("--> ENDE \n");
        }
        else
            printf("Nur GET-Anfragen werden bearbeitet!\n");
    }

    Nun, das Programm tut bis hierhin was es soll, jedenfalls via Telnet. Das Problem ist, dass der FF scheinbar HTTPTML/1.1 requestet.
    Kann man den Firefox irgendwie 'toleranter' schalten?

    Das interessante ist, dass durchschnittlich jedes 2. Mal die Page angezeigt wird, wenn ich einfach nochmal einen Refresh durchfuehre, kann es sein, dass die Page mit der Fehlermeldung "The connection was reset" terminiert wird.

    Im Fenster des Programms "webserver" auf Konsolenebene wird jedoch der richtige Request / bzw. nichts auffaelliges angezeigt.
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    OPENING: >index.html<
    EXTENSION: >html<
    --> ENDE
    Verbindungsaufbau erfolgreich
    GET /index.html HTTP/1.1
     
    OPENING: >index.html<
    EXTENSION: >html<
    --> ENDE
    Verbindungsaufbau erfolgreich
    GET /index.html HTTP/1.1
     
    OPENING: >index.html<
    EXTENSION: >html<
    --> ENDE
    Verbindungsaufbau erfolgreich
    GET /index.html HTTP/1.1
     
    OPENING: >index.html<
    EXTENSION: >html<
    --> ENDE
    Verbindungsaufbau erfolgreich
    GET /index.html HTTP/1.1
     
    OPENING: >index.html<
    EXTENSION: >html<
    --> ENDE

    Hat da jemand ne Idee?
    Geändert von huebstAr (14.12.11 um 22:11 Uhr)
     

  11. #11
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    HTML1.1: Du meinst HTTP. Großer Unterschied.

    Kannst du die Telneteinagbe/ausgabe auch mal zeigen?

    PS: content-length...
     
    Netiquette (vA §15) und Nutzungsregeln (vA §4.8) einhalten! Programmcode in Codetags/Codeboxen.
    Sehr gute Beiträge bitte Bewerten (Stern darunter oder "Danke").
    "Funktioniert nicht" ist zu ungenau! Code, Fehlermeldungen, Verhalten des Programms, ...?

  12. #12
    huebstAr huebstAr ist offline Mitglied
    Registriert seit
    Jun 2009
    Beiträge
    13
    Hi,
    sorry, meinte natuerlich HTTP/1.1.

    Hier mal 2 Screenys:
    1. 2. 3. Request sind vom Telnet-Fenster, also ohne HTTP/1.1

    4. und 5. request sind vom Firefox.

    kleiner Webserver in C-snapshot2.png
    kleiner Webserver in C-snapshot1.png

    Was meinst Du mit Content-Length? Ist hier was falsch? Sehe da nun nichts >x
     

  13. #13
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Also, nocheinmal:
    Außer dem Content-Type musst du die Content-Length angeben.
    Als Zahl, wieviel Chars (oder Byte?, muss nachschauen) die Datei hat.

    Der Zeichensatz ist auch eines der essentiellen Sachen, die möglichst dabei sein sollten.

    Dein Header wird nirgends geschickt,

    Zum Senden (Header und Daten) über den Socket solltest du Socketfunktionen verwenden und deren Eigenheiten beachten (uU. wird nicht mit einem Aufruf alles gesendet).

    Und wenn FF HTTP1.1 verlangt (was übrigens nicht umstellbar ist und auch verwendet werden sollte, da 1.0 mit heutigem Zeug Probleme hat), dann gib ihm im Header doch HTTP1.1, nicht 1.0.
    huebstAr bedankt sich. 
    Netiquette (vA §15) und Nutzungsregeln (vA §4.8) einhalten! Programmcode in Codetags/Codeboxen.
    Sehr gute Beiträge bitte Bewerten (Stern darunter oder "Danke").
    "Funktioniert nicht" ist zu ungenau! Code, Fehlermeldungen, Verhalten des Programms, ...?

  14. #14
    Avatar von Bratkartoffel
    Bratkartoffel Bratkartoffel ist offline gebratene Kartoffel
    tutorials.de Premium-User
    Registriert seit
    Jun 2007
    Ort
    Passau (Niederbayern)
    Beiträge
    1.394
    Hi,

    dem Firefox ist es relativ egal, ob er nun HTTP/1.0 oder 1.1 Antworten bekommt. Ich würde auch auf die fehlende Angabe des "Content-Length" Headers in der Antwort tippen.

    Grüße,
    BK
    huebstAr bedankt sich. 
    Über eine gute Bewertung freut sich jeder ;)
    Bitte erledigte Threads als "Erledigt" markieren.

    "Though a program be but three lines long, someday it will have to be maintained.''
    -- Geoffrey James, "The Tao of Programming"

  15. #15
    huebstAr huebstAr ist offline Mitglied
    Registriert seit
    Jun 2009
    Beiträge
    13
    Moin Zusammen!

    Danke erstmal für die Tipps, habe mich noch ein wenig damit beschäftigt und bin auch 'ne Ecke weiter gekommen (meiner Ansicht nach zumindest )

    Also stand der Dinge:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    
    //
     
    //----------------------------------------------------------------------------
    // Einbinden der Headerdateien
    #include <sys/types.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <errno.h>
     
     
    // Prototypen der verwendeten Funktionen
    int deploy_server();
    void process_request(int result_accept);
     
    // Struktur mit erlaubten MIME-Types
    struct {
        char *ext;
        char *filetype;
          }
    extensions[] =
        {
        {"gif", "image/gif"},
        {"jpg", "image/jpg"},
        {"jpeg", "image/jpeg"},
        {"png", "image/png"},
        {"zip", "image/zip"},
        {"gz", "image/gz"},
        {"tar", "image/tar"},
        {"htm", "text/htm"},
        {"html", "text/html"},
        {0,0}
        };
     
     
    int main()
    {
        int     sock=-1,
            source=0,
            result_accept=0,
            pid=-1,
            len_addr=0,
            status=0;
        struct sockaddr_in requestor;
       
        printf(".\n");
        printf(".\n");   
        printf("Webserver v1.3 gestartet\n");
        printf(".\n");
        printf(".\n");
     
     
        do {
     
     
            sock = deploy_server();
            if(sock<0)
            {       
                printf("Fehler beim Deployen des Servers!\n");
                printf("<RETURN> für Neuversuch\n\n");
                getchar();
            }
     
     
        }while(sock < 0);
     
     
        while(1)
        {
            len_addr = sizeof(source);
            result_accept = accept(sock, (struct sockaddr*) &source, &len_addr);
           
            if(-1 == result_accept)
            {
                printf("Fehler beim Verbindungsaufbau\n");
            }
            else
            {
                printf("Verbindungsaufbau erfolgreich\n");
            }
     
     
            pid = fork();
           
            if(-1 == pid)
            {   
                printf("Fehler beim erstellen des Sohnprozesses!\n");
            }
           
            if(0 == pid)        // wenn Sohnprozesses
            {
                process_request(result_accept);
                exit(0);
            }
        waitpid(-1, &status, WNOHANG);
            close(result_accept);
        }
    }
     
     
    int deploy_server()       
    {
        int     sock,
            result_bind=5;
        struct     sockaddr_in adressinfo;
     
     
        sock = socket(AF_INET, SOCK_STREAM, 0);
       
        bzero(&adressinfo, sizeof(adressinfo));
       
        adressinfo.sin_family = AF_INET;
        adressinfo.sin_port = htons(80);
        adressinfo.sin_addr.s_addr = INADDR_ANY;
       
        result_bind = bind(sock, (struct sockaddr*) &adressinfo, sizeof(adressinfo));
     
     
        if(result_bind == -1)
        {   
            printf("Fehler bei Bind");
            return -1;   
        }
     
     
        listen(sock, 5);
        return(sock);
    }
     
     
    void process_request(int sock)
    {
        char        sendbuffer[8096],
                request[8096],
            filename[8096],
            buffer,
            ex_extension[4];
        int     i=0,
                k=0,f=0,
                ext_laenge=0,
                anzahl=0,
                file_descript=0;
        char        *format;
       
            bzero(&request, sizeof(request));
        bzero(&filename, sizeof(filename));
        bzero(&sendbuffer, sizeof(sendbuffer));
        bzero(&ex_extension, sizeof(ex_extension));
       
        while(i < sizeof(request)-1)    // solange die Länge des Strings nicht überschritten wird
        {
            if(    read(sock, &buffer, 1) > 0       // Solange ein Zeichen gelesen werden kann
                && buffer != '\n'               // UND kein Zeilenumbruch
                && buffer != '\r')
            {       
                request[i] = buffer;        // weiter einlesen
                i++;
            }
            else
            {
                request[i] = '\0';          // Sonst String abschließen
                break;                  // und Schleife abbrechen
            }
        }
     
     
        // Kontrollausgabe der Anfrage
        for(k=0; k< sizeof(request); k++)
            printf("%c", request[k]);
        printf("\n\n");
       
        // Prüfen ob Get-Anfrage (nicht Case-Sensitive)
        if(!strncmp(request, "GET ", 4) || !strncmp(request, "get ", 4)) // falls GET
        {   
          i=5;                          // Startwert des Index, GET wird ignoriert
          f=0;
        
          if(!strncmp(&request[5], "\0", 1) || !strncmp(&request[5], " ", 1))    // Wenn keine Seite angegeben
          {     
              strcpy(request, "GET /index.html");       // String auf index.html setzen                              
          }
        
          while(strncmp(&request[i], " ", 1))       // SOLANGE KEIN Leerzeichen erreicht
          {      
          strncpy(&filename[f], &request[i], 1);    // Zeichen an Filename anhängen
          f++; i++;
          }
     
     
          i=0;
          
          // Extensions extrahieren
          while(strncmp(&filename[i], ".", 1))      // Punkt suchen
          {     
              i++;
          }
          strcpy(ex_extension, &filename[i+1]);     // Fileextension extrahieren
        
          // Extension zuordnen
          i=0;
          format = (char *) 0;
          while(extensions[i].ext != 0)
          {
            if(!strncmp(ex_extension, extensions[i].ext, strlen(ex_extension)))
            {
            format = extensions[i].filetype;
            printf("FORMAT: %s\n", format);
            break;
            }
            i++;
          }     
          
          if(format != 0)
          {
            printf("OPENING: >%s<\n", filename);
            printf("EXTENSION: >%s<\n", ex_extension);
            file_descript=open(filename, O_RDONLY);     // Angefordertes File öffnen
            
            if(file_descript != -1)
            { 
            strcpy(request, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
            printf("size> %i\n=========================================================\n\n", strlen(request));
            write(sock, request, strlen(request));     
              
            while((anzahl=read(file_descript, sendbuffer, sizeof(sendbuffer))) > 0)
                write(sock, sendbuffer, anzahl);
            
            getchar();
            
            close(file_descript);
            }       
            else
            printf("Fehler! File konnte nicht geöffnet werden!\n");
         
          }
          else
            printf("Falscher MIME-Type!\n");
        }
        else
            printf("Nur GET-Anfragen werden bearbeitet\n");
    }

    Jetzt ist mir folgendes aufgefallen:
    Über Telnet wird alles übertragen (inkl. Header, anschließend die angeforderte Seite) - Soweit sogut. Das Problem ist tatsächlich nun, dass die Browser nach sehr kurzer (kaum sehbarer Zeit) die Seite verlässt mit der Fehlermeldung "The connection was reset".

    Daher habe ich mal das getchar() eingebaut und siehe da, die Page bleibt im Browser, leider eben nur solange mit Enter bestätigt wird.

    Was kann ich dagegen tun?

    Desweiteren habe ich das Problem, dass ich gerne nachträglich die Art der Anforderung (also HTML, JPG, etc.) einfügen würde. Die Zuweisung klappt schon und in der Variable "format" steht auch der richtige MIME-Type.

    Leider habe ich es noch nicht geschafft, diesen in den HTTP-Header einzufügen :\
    Hat da jemand ne fixxe Idee?

    Gruß
     

Ähnliche Themen

  1. Antworten: 3
    Letzter Beitrag: 27.12.10, 11:27
  2. Eigener Webserver: Apache Webserver - jBoss
    Von janpaet im Forum Hosting & Webserver
    Antworten: 0
    Letzter Beitrag: 27.08.07, 20:36
  3. kleiner als 1px?
    Von vato im Forum Photoshop
    Antworten: 21
    Letzter Beitrag: 03.04.02, 23:21
  4. Kleiner Webserver mit PHP
    Von Neuk im Forum Hosting & Webserver
    Antworten: 6
    Letzter Beitrag: 17.02.02, 14:08