tcp server, timout beim recv



  • Hi,
    ich habe frage einen TCP socket in einer schleife ab

    listen(listenfd, 10);
        //�ffne Socket,
        len = sizeof(cli_addr);
        connfd = accept(listenfd,(struct sockaddr *) &cli_addr,&len);
        if (connfd < 0)
          error("ERROR on accept");
    
        //connfd = accept(listenfd, (struct sockaddr*) NULL, NULL);
    
        /**Receive**/
    
       // if(readable()){
            recv(connfd, recByte, sizeof (recByte), 0);
        //}else{
         //   printf("Keine Daten empfangen\n");
        //}
    
        recv(connfd, recByte, sizeof (recByte), 0);
    

    nun blockiert der mir mein Programm weil der ja wartet bis etwas rein kommt...

    wie kann ich dies umgehen? habt ihr paar beispiele?

    am liebsten wäre es wenn der paar ms wartet, wenn nichts kommt, dann läuft der weiter und macht die nächste Routine



  • Dafür gibt es selecet .

    Bei http://www.zotteljedi.de/ findest du socket-tipps und auch ein socket-buch.
    Schau es dir mal an.



  • Ich habe es nun mit

    struct timeval tv;
    
    	tv.tv_sec       = 1;
    	tv.tv_usec      = 0;
    
        if (setsockopt(listenfd,SOL_SOCKET,SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval))  == -1){
            perror("setsockopt");
            exit(1);
        }
    

    versucht... läuft aber nicht... bleibt in der TCP_schleife hängen....

    wo muss ich das denn überhaupt hinsetzen? hinterm acctept?
    oder hinter meinem socket()



  • Nimm select :

    int my_check;
    
    do
    {
            if(select-call() == HABN_TIMEOUT)
            {
                    /*Hier muss noch aufgeräumt werden - weil alles, was die Gegenseite uns geschickt hat,
                    **unvollständig ist.*/
                    break;
            }
    
            /*Hier machen wir Prüfung auf < 1, nicht auf < 0. 0 wären 0 Bytes, die beschrieben wurden, aber
            **mit select haben wir ja schon geprüft, ob wir Daten zum Schreiben haben. 0 ist also irgendein
            **Fehler, oftmals "Peer hat den Socket geschlossen".*/
            if(recv-call() < 1)
            {
                    /*Auch hier wieder aufräumen, und dann ...*/
                    break;
            }
    
            /*Und hier machst du eine Prüfung, ob die Daten, die du bekommen hast, gut aussehen.
            **Drei Stadien hast du immer: Kaputt, Weitermachen, OK. Kaputt heißt, dass die Daten Müll sind
            **und das weiter einlesen nix bringt. Weitermachen heißt, dass sie gut aussehen, aber da fehlt
            **noch was. OK ist aufhören, wir haben genug, alles in Ordnung.*/
            my_check = protocol-check();
    }
    while(Imy_check == WEITERMACHEN);
    

    Warum ist das eigentlich immer noch eine Frage da draußen? Gibt es nicht bereits unzählige Artikel darüber, wie man Timeout-Handling macht? Oder lest ihr die alle nur nicht?



  • mitch_m schrieb:

    Ich habe es nun mit

    struct timeval tv;
    
    	tv.tv_sec       = 1;
    	tv.tv_usec      = 0;
    	
        if (setsockopt(listenfd,SOL_SOCKET,SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval))  == -1){
            perror("setsockopt");
            exit(1);
        }
    

    versucht... läuft aber nicht... bleibt in der TCP_schleife hängen....

    wo muss ich das denn überhaupt hinsetzen? hinterm acctept?
    oder hinter meinem socket()

    Also das setzt du hinter den Funktionsaufruf:

    listenfd = socket(AF_INET, SOCK_STREAM, 0)  // return-Wert überprüfen
    if (setsockopt(listenfd,SOL_SOCKET,SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval))  == -1){
            perror("setsockopt");
            exit(1);
        }
    /*
     *  solltest du vieleicht auch mit SO_SNDTIMEO und TCP_NODELAY machen
     *  diese machen send() blockadefrei und schicken auch kleine Packete
     */
    if (setsockopt(listenfd,SOL_SOCKET,SO_SNDTIMEO,(struct timeval *)&tv,sizeof(struct timeval))  == -1){
            perror("setsockopt");
            exit(1);
        }
    int flag = 1;
    if (setsockopt(listenfd,IPPROTO_IP,TCP_NODELAY, (void*)&flag, sizeof(int)) == -1){
            perror("setsockopt");
            exit(1);
        }
    /*
     *  Hiernach je ob Server oder Client
     *  Pseudo-Code
     */
    //  Server
    bind
    listen
    accept
    //  client
    connect
    

    Ich würde aber dein timval deutlich kleiner machen. Ich verwende tv.tv_sec=0 und tv.tv_usec=300, da dein Programm sonst immer wieder für 1 Sekunde hängen wird (eventuell auslagern in pthread?).
    Du wirst aber Problem beim send() und recv() bekommen. Hier musst du dir eine gute Routine überlegen, wie du große Daten empfangen oder senden kannst. Die blockierende send() bzw. recv() nehmen dir hier eine Menge Denkarbeit ab. Aber du solltest keine Angst davor haben, trotzdem die Timeouts einzusetzen. Habe so einen Server und Client geschrieben, welcher Bilder von einer Kamera vom Server an den Client schickt. Einfach recv() und send() in while-Schleife packen und den Return-Wert + Errno checken, dann bekommt man eine gute Routine hin.


Log in to reply