socket / fork() problem



  • Hi,
    ich habe auf einer RedHat Linux 7.3 Kiste einen
    Daemon laufen, welcher auf einen bestimmten Port lauscht und
    auf Client anfragen (natürlich auf mehrere(via fork)) wartet.
    Der Daemon startet im Hintergrund wieder via fork().
    Somit lauscht der Daemon im Hintergrund und nimmt auch Client Anfragen
    entgegen.
    Sende ich nun Daten vom Client an den Server, wird nach einer
    definierten endekennung die Connection geschlossen(scheinbar),
    zumindest Verliert der Client die Verbindung.
    Doch Serverseitig besteht die Verbindung weiterhin.
    D.H.: kille ich den Daemon, via SIGTERM, bleibt die Verbindung
    weiterhin bestehen, trotz schliessen des Sockets!
    Somit kann der Daemon beim neustart denn Port nicht mehr binden, erst
    nach einer weile, steht er wieder zur Verfügung!
    eine sehr nervige Angelegenheit, da ich immer warten muss, bis der
    Socket von selbst schliesst!

    Hier mein Quellcode:

    //-------------------------------------------------
    void term(int sig)                              //SIGTERM Handler
    {  
      cout <<"raus";
      close(curSock);
      close(sock);
      exit(1);
    }
    
    int main(int argc, char **argv) {
    #define buflen 1024
        int curlen = buflen;
        char inbuf[buflen+1];
        char ende[]="!";                            //Endekennung
        int status;
        int status_main;
        int port = 3737;                            //Port
        struct sockaddr_in adr;
        struct sockaddr_in clientName;
        struct protoent *proto = getprotobyname("tcp");
        int protocol = (*proto).p_proto;    
    
        if ((sock = socket(PF_INET, SOCK_STREAM, protocol)) == -1)
    {       //Socket erstellen
            printf("Error creating socket.");
            return 1;
        }
    
        adr.sin_family = AF_INET;
        adr.sin_port = htons(port);
        adr.sin_addr.s_addr = htonl(INADDR_ANY);
    
        if(bind(sock, (struct sockaddr*)&adr, sizeof(adr)) == -1) {     //Socket
    an Port binden
            //while (bind(sock, (struct sockaddr*)&adr, sizeof(adr)) ==
    -1){    //Wenn belegt, versuche erneut
             //sleep(1);
            //}
            printf("Error bind on socket.");
            return 1;
        }
    
        if(listen(sock, 2)) {                           //Nun lausche auf Port
            printf("Error listening on socket.\n");
            return 1;
        }
    
        status_main = fork();                           //Haupt-fork Programm läuft im
    Hintergrund
        if(status_main == -1) {
         fprintf(stderr, "fork failed.\n");
        } 
        if(status_main>0) {                          //Vaterprozess
         close(sock);
         exit(0);
        } 
        else {                                  //Child Prozess
        }
        setsid();                               //Prozessgruppenführer
        signal(SIGTERM, term);                          //Wenn Sigterm --> term()
    
        while(1) {                              //Endlosschleife
         unsigned int clientLength = sizeof(clientName);
         curSock = accept(sock, (struct sockaddr*)
    &clientName,&clientLength);
         if(curSock == -1) {                            //Socket nicht akzeptiert
          printf("Error accept().\n");
          return -1;
         }  
         status = fork();                           //Fork--> Handling für mehrere Client
    Anfragen
         if(status == -1) {
          fprintf(stderr, "fork failed.\n");
         } 
         if(status>0) {                              //Vaterprozess
          close(curSock);
          exit(0);
         } 
         else {                                 //Childprozess für jede Client Anfrage
          while((curlen = read(curSock, inbuf, buflen)) > 0 ) {          //Lese vom
    Client
           inbuf[curlen] = 0;
           if (!strcmp(inbuf,ende)){                        //Wenn Endekennung erreicht
            cout <<"Verbindung wird getrennt!";
            close(curSock);                         //Conection schliessen
            exit(0);
           }
          }
          //return 0;
         }
        }                                   //Ende Endlosschleife
    }                                       //Ende Main 
    
    //-------------------------------------------------
    

    Ich hoffe, Ihr könnt mir weiterhelfen!
    Vielen Dank
    mfg Christof



  • hab keine Zeit groß nachzuforschen, aber guck dir mal setsockopt(2) / socket(7) => SO_REUSEADDR an



  • naja, eine kleine Code Kritik von mir

    cout <<"raus";
    //...
    printf("Error creating socket.");
    

    iostream und stdio funktionen zu mischen ist nicht gut, wenn man nicht ostream::sync_with_stdio() aufruft (aber man sollte generell C++ und C Mischungen vermeiden). Außerdem würde ich perror benutzen, bei einem Fehler, da die Fehlermerlund dann mit ausgegeben wird

    #define buflen 1024[/url]
    
    #define ist schlecht! mach lieber const size_t buflen=1024;
    
    [code type="c++"]char ende[]="!";
    

    dafür reicht doch auch ein char ende='!'; dann sparst du auch das teure strcmp

    int protocol = (*proto).p_proto;
    

    dafür haben wird doch den schönen -> Operator

    int protocol=proto->p_proto;
    
    if(status_main == -1) {
    //...
    if(status_main>0) {
    //...
    else {
    

    dafür bietet sich doch switch an, was bei einigen Compilern schneller ist als if.

    Außerdem sollte man Daemonen 2 mal forken! Schau dir am besten mal den Code hier an wie bekomm ich mein prog dazu das es als daemon läuft



  • Hi,

    Somit kann der Daemon beim neustart denn Port nicht mehr binden, erst
    nach einer weile, steht er wieder zur Verfügung!

    Ist voellig normal, da es sein kann, dass vom Verbindungspartner noch
    Packete ankommen, die nur laenger gebraucht haben. Soweit ich weiss,
    bleibt der Port 'gebinded' (was fuer ein schoenes Wort ;)), bis die
    doppelte Zeit, die ein Packet im Internet ueberleben kann ohne das es
    sein Ziel erreicht, verstrichen ist. Das kann einige minuten dauern.

    Loesungen dazu, wurden ja schon genannten.

    mfg
    v R



  • @Bashar :
    Klasse!!!
    Was mann mit nem zweizeiler(naja 1 1/2) alles erreicht! Hat wunderbar geklappt!!
    Vors bind einfach:

    int on = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
    

    Vielen Dank!!!

    @kingruedi:
    Danke für die hilfreichen Tips!!
    momentan kann mann ja noch nicht von umbedingt sauberen Code reden,
    das iss mir bewusst!
    Werde da noch ein bissl aufräumen müssen!
    Werden mir dabei deine Anregungen zu gemüte führen!
    Der Sinn des 2mal forken ist mir allerdings noch nicht so bewusst!
    Vielen Dank!!!

    gruss Christof



  • zum Thema 2. fork

    http://www.faqs.org/faqs/unix-faq/programmer/faq/ 1.7

    3. `fork()' again so the parent, (the session group leader), can exit.
    This means that we, as a non-session group leader, can never regain a
    controlling terminal.


Anmelden zum Antworten