Problem mit sockets / http --> Connection: Keep-Alive



  • Hi !
    Ich beschäftige mich schon seit ein paar tagen mit dem http protokoll....

    Also einfach dumm gesagt: ich will eine website auf einem webserver abrufen...
    Wenn ich jetzt einfach einen socket öffne und eine get-anfrage stelle den socket danach wieder schließe, funktioniert alles wunderbar....

    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    
    #ifdef _WIN32
    #include <winsock.h>
    #include <io.h>
    #else
    #include <sys/types.h>
    #include <sys/socked.h>
    #include <netinet/in.h>
    #include <netbd.h>
    #include <stdlib.h>
    #include <string.h>
    #define closesocket(s) close(s)
    #endif
    
    #define HTTP_PORT 80
    
    struct sockaddr_in server;
    struct hostent *host_info;
    unsigned long addr;
    int sock;
    char buffer[8192];
    int count;
    
    void request()
    {
      for(int i = 0;i<sizeof(buffer);i++)buffer[i]=(char)0;
      sprintf(buffer,"GET /index.php HTTP/1.1\r\nHost: 192.168.2.2\r\nConnection: Keep-Alive\r\n\r\n");
      send(sock,buffer,strlen(buffer),0);
    
      do{
        count = recv(sock,buffer,strlen(buffer),0);
        write(1,buffer,count);
      }while(count > 0);
    }
    
    void open()
    {
    
    #ifdef _WIN32
      short wVersionRequested;
      WSADATA wsaData;
      wVersionRequested = MAKEWORD(1,1);
      if(WSAStartup(wVersionRequested, &wsaData) != 0)
      {
        fprintf(stderr, "Failed to init Windows Socked\n");
        exit(1);
      }
    #endif
      //Erzeugen des Sockets:
      sock = socket(PF_INET,SOCK_STREAM,0);
      if(sock < 0)
      {
        perror("failed to create Socket");
        exit(1);
      }
    
      //Socked Addy erzeugen:
      memset(&server,0,sizeof(server));
    
      if((addr=inet_addr("192.168.2.2")) != INADDR_NONE)
      {
        memcpy((char *)&server.sin_addr,&addr,sizeof(addr));
      }
      server.sin_family = AF_INET;
      server.sin_port = htons(HTTP_PORT);
    
      if(connect(sock,(struct sockaddr*)&server,sizeof(server)) < 0)
      {
        printf("Port 80 N/A\n");
        //exit(1);
      }else
      {
        //request();
      }
    
    }
    
    int main(int argc, char *argv[])
    {
      system("cls");
    
      while(1)
      {
        open();
        request();
        Sleep(1000);
        closesocket(sock);
      }
      return 0;  
    }
    

    Veruche ich jetzt den socket offen zu halten, scheint das auch einen moment lang zu funktionieren, der server gibt mir auch an das Keep-Alive Timer = 5sec...

    hier mal der Code:

    int main(int argc, char *argv[])
    {
      system("cls");
    
      open();   
      while(1)
      { 
        request();
        Sleep(1000);
      }
      closesocket(sock); 
      return 0;  
    }
    

    Also der socket bleibt definitiev länger als 5sec offen....
    Kurz darauf(mal nach 10s,mal nach 5s) wird die connection vom server geschlossen
    Was dabei auffällt ist das der Buffer in dem Moment mit merkwürdigem krahms voll geschrieben ist (nur unter windows unter linux leider nicht mal sowas)...

    hp
          └s  $q  îp          ýs  Hq  ┤p           t  pq  └p          ht  |q
                      ▄q  Ûq  ¶q  ³qr  ►r  ↑r          "r  .r  <r  Hr  Xr  vr  ~r  É
    r          ár          ¬r  ║r  ╩r  Ïr  Ûr  ¶r  ■r  ♠s  ►s  ∟s  $s  .s  6s  @s  H
    s  Rs  \s  fs  ps  zs  äs  Äs  ÿs          UjíqJíqS.íqß.íqp.úq'Líq◄Bíq        ♣U
    â|·╩ü|¯♀â|│┴à|²Iä|F$Ç|È→Ç|a║Ç|        ♥♥└w        Ù¯¥w┼±¥w█±¥w|S└wfU└wÂ×└wdz┬w°M
    └wù┐w│k└w5N└w~×└w‼♫┴w←┬┐w─┐wpo┴w­u┴w‗m└wj↑┴wÈO└w1¨└wáx┴wÃô┐w    ▼ WSAStartup  &
     connect 4 htons 5 inet_addr = recv  C send  H socket  ☺ AddAtomA  £ ExitProcess
     ░ FindAtomA ¦ GetAtomNameA  Ò☻SetUnhandledExceptionFilter ´☻Sleep ▲♥VirtualProt
    ect  !♥VirtualQuery  m _write  7 __getmainargs M __p__environ  O __p__fmode  c _
    _set_app_type  ë _assert ô _cexit
    ☺_iob  ⌂☺_onexit ¬☺_setmode  G☻abort N☻atexit  \☻exit  k☻fprintf q☻free  ñ☻mallo
    c  ¬☻memcpy  ¼☻memset  »☻perror  ▒☻printf  ┬☻signal  ┼☻sprintf Ð☻strlen  Ó☻syste
    m     p   p   p   p   p   p   p  WSOCK32.DLL ¶p  ¶p  ¶p  ¶p  ¶p  ¶p  ¶p  ¶p  KER
    NEL32.dll    (p  msvcrt.dll  <p  <p  <p  <p  <p  <p  <p  <p  <p  <p  <p  <p  <p
     <p  <p  <p  <p  <p  <p  <p  <p  <p  <p  msvcrt.dll
    

    Wenn ich mir das ganze mit Wireshark angucke fällt mit ausser dem RST nichts auf...

    Freue mich jetzt schon auf die antworten, denk da schon seit 3 tagen drüber nach...

    Mfg Benny



  • Hallo

    Also zum Keep-Alive kann ich folgendes sagen: Server können es unterstützen, müssen es aber nicht.
    Das Schließen einer Verbindung kann -soweit ich mich erinnere- in seltenen Fällen auch absichtlich erfolgen, wenn der Server keine Content-Length kennt, weil der Inhalt von einem Script dynamisch erzeugt wird. In so einem Fall kann nur das Schließen der Verbindung die HTTP-Übertragung abschließen.

    Jetzt zum Problem:
    Wenn dein Server Keep-Alive umsetzt wird deine recv-Schleife, nachdem sie die Daten der ersten Antwort empfangen hat, blockieren und auf weitere Daten des Servers warten. Der Server wird dir aber keine Antwort schicken, weil du ihm ja keinen weiteren Request geschickt hast. Nach X-Sekunden tritt beim Server ein Timeout auf und er schließt die Verbindung, was dein recv mit "0" zurückkehren lässt. Die Verbindung ist nun geschlossen. Wenn du nun erneut über den Socket Daten versenden willst, kehrt "send" mit -1 zurück und dein Socket ist im Error-Modus. Jetzt wird dir "recv" auch -1 zurückgeben und dein "write" interpretiert den "count" als unsigned integer und will vermutlich deinen gesamten Speicher ausgeben, was es abstürzen lässt ... manchmal siehst du dabei diverse Speicher-Geheimnisse 😉

    Du solltest daher in deinem Code auch alle Fehlerfälle beachten wenn "send" und "recv" -1 zurückgeben.
    Der vereinfachte Ablauf des Clients sollte so sein:
    (1) Verbindung aufbauen
    (2) Request senden
    (3) Stückweises Einlesen der Antwort bis zum Ende des HTTP-Headers \r\n\r\n
    (4) Auswertung des HTTP-Headers - besonders: "Connection" und "Content-Length"
    (5a) Keep-Alive: Genau soviele Bytes lesen, wie in Content-Length steht.
    (5b) Close: So lange lesen, bis recv "0" zurückgibt
    (6a) Keep-Alive: Falls ein weitere Request ansteht -> ab zu Schritt 2
    (6b) Close: Verbindung schließen und Socket freigeben.

    cu 😃



  • Danke XOR !!!

    Ich denke das war eine sehr gute fehleranalyse !
    Irgendwie hab ich gedacht, ich könnte mir das analysieren der rückgabe werte vorerst sparen, auf kurz oder lang wollte ich natürlich auf jedl. fehler überprüfen... Tja, so leicht stellt man sich ein eigenes Bein 🙂

    Ich denke mit der vorgehensweise kann ich was anfangen !
    erst mal Super Herzlichen Dank !

    Mfg Benny



  • Hi !
    Also der tipp von XOR war perfekt... in zukunft werde ich immer rückgabe werte auswerten 🙂

    Ich hab irgendwie noch ein kleines logik problem mit sprintf... das wurmt mich 🙂

    sprintf(buffer,"GET /%s HTTP/1.1\r\n",requestedFile);
      sprintf(buffer,"%s",buffer,requestedFile);
      sprintf(buffer,"%sHost: %s\r\nConnection: Keep-Alive\r\n\r\n",buffer,this->ip);
    

    funktioniert soweit... aber...
    müsste in der zweiten zeile nicht eigendlich sowas stehen:
    sprintf(buffer,"%s%s",buffer,requestedFile);

    eigendlich mache ich sowas immer mit pointern, nur finde ich sprintf in dem fall schöner, weil man im code direkt sehen kann was gemacht wird ohne erst mal die pointer zu zerfetzen...

    also mal ganz im ernst ?!? was habe ich bei sprintf nicht verstanden ?

    Mfg Benny



  • Bei der 2. Zeile wäre ein strcat auch nicht schlecht. 🙂

    Ansonsten werte den Rückgabewert von sprintf aus:

    int pos = 0;
    
    pos + = sprintf(buffer+pos, "GET /%s HTTP/1.1\r\n", requestedFile);
    pos + = sprintf(buffer+pos, "%s",requestedFile);
    pos + = sprintf(buffer+pos, "Host: %s\r\nConnection: Keep-Alive\r\n\r\n", this->ip);
    


  • Hi !
    also da ist ja mein problem...
    strcat funktioniert in dem fall auch nicht so wie es soll... ich werde gleich mal die rückgabe werte angucken, ich könnt mir gut vorstellen das da ein problem mit den CR+LF's ist...

    auf jeden fall fügen

    strcat(buffer,requestedFile);
    und
    sprintf(buffer,"%s%s",buffer,requestedFile);
    den string requestedFile an der falschen stelle im Buffer ein...

    naja... bezüglich der rückgabe werte werde ich mich noch mal melden,
    ansonsten baue ich mir gerade nen eigenes strcat...

    Mfg Benny


Anmelden zum Antworten