winsock - verbindungsaufbau läuft und läuft und bricht nicht ab...



  • Hi,

    folgendes, ich baue mit winsock eine http verbindung zu mehreren servern auf (blocking connect), siehe bsp unten.

    soweit so gut. kommt eine verbindung zustande gehts weiter im programm.. kommt keine zustande bringt er mir ne fehlermeldung (bzw. speichert diese)

    jetzt habe ich aber bei einem server aktuell das problem das der verbindungsaufbau gar nicht mehr aufhört. es kommt weder eine verbindung zustande noch wird der verbindungsaufbau abgebrochen.

    er "hängt" sozusagen einfach beim ersten connect... aber sollte er nicht nach 15 sec abbrechen wenn keine verbindung zustande kommt oder es zu lange dauert ??
    so macht er das ja wenn ein server gar nicht erreichbar ist...

    EDIT: das problem liegt daran das zwar der router erreichbar ist(ping kommt zurück), aber der http-server der dahinter steht ist nicht erreichbar...

    was könnte ich in diesem fall tun?

    anbei der ausschnitt.. wie gesagt ein simpler connect

    //Winsock starten
        int connect_handle;
        SOCKET new_socket;
        SOCKADDR_IN addr;     
        WSADATA wsa;
    
        connect_handle = WSAStartup(MAKEWORD(2,0),&wsa);
    
        //winsock gestartet ??
        if(connect_handle != 0) {
            //error handling....
    
        } else {
    
            //std::cout << "WinSock gestartet!\n";
            //Socket definieren
            new_socket = socket(AF_INET,SOCK_STREAM,0);
    
            //Socket erstellt?
            if(new_socket == INVALID_SOCKET) {
                //error handling...
                WSACleanup();
    
            } else {
    
                //addr auf null setzen
                memset(&addr, 0, sizeof(SOCKADDR_IN));
    
                //und wieder füllen
                addr.sin_family = AF_INET;
                addr.sin_port = htons(80);
                addr.sin_addr.s_addr = inet_addr(serverip.c_str());
    
                //Verbindung aufbauen
                bool connect_success = false;
                connect_handle = connect(new_socket, (SOCKADDR*)&addr, sizeof(SOCKADDR));
    
    // TRY IT 5 TIMES  ( MAYBE THERE'S A SLOW SERVERS... )
    //************************************************
    //  1. Connect Versuch
    
                if(connect_handle == SOCKET_ERROR) {
    
                    //etc
    


  • Wie kommst du drauf, daß das timeout 15 Sek. beträgt?

    Bei connect müsstest du dein timeout z.B. mit WaitForSingleObject testen.
    setsockopt um timeout zu kontrollieren funktioniert nicht mit connect.



  • nach der in windows eingestellten zeit bricht doch connect ab und gibt einen fehler zurück ?? oder bin ich da aufm falschen dampfer ??

    waitforsingleobject benutzt ich doch bei recv? wie soll das denn bei connect funktionieren? connect ist doch ein blocking element.. ?



  • taurus schrieb:

    waitforsingleobject benutzt ich doch bei recv? wie soll das denn bei connect funktionieren? connect ist doch ein blocking element.. ?

    Nein, bei einem nonblocking socket kehrt connect sofort zurück.
    Nach dem Aufruf musst du dann iwie prüfen, ob eine Verbindung hergestellt wurde.

    Wenn das nicht über WFSO geht, kannst du den Socket Status über recv abfragen.



  • taurus schrieb:

    nach der in windows eingestellten zeit bricht doch connect ab und gibt einen fehler zurück ?? oder bin ich da aufm falschen dampfer ??

    waitforsingleobject benutzt ich doch bei recv? wie soll das denn bei connect funktionieren? connect ist doch ein blocking element.. ?

    Klar bricht connect irgendwann mal ab, aber mit Sicherheit nicht nach 15 Sek sondern viel, viel später.

    Ich mach's bei blocking sockets so, daß ich auf meinen event warte, der z.B. nach dem ersten erfolgreichen recv gesetzt wird.

    Falls der nicht rechtzeitig gesetzt wird, kill ich den socket mit

    shutdown(m_bsocket, SD_BOTH);
    // und je nachdem ob ich ungeduldig bin oder nicht http://msdn.microsoft.com/en-us/library/ms738547%28VS.85%29.aspx :
    if( !graceful )
    {
    	LINGER  lingerStruct;
    
    	lingerStruct.l_onoff = 1;
    	lingerStruct.l_linger = 0;
    	setsockopt(m_bsocket, IPPROTO_TCP, SO_LINGER, reinterpret_cast<char *> (&lingerStruct), static_cast<int> (sizeof(lingerStruct)) );
    }
    closesocket( m_bsocket );
    

    Du brauchst natürlich noch 1, 2 Kontrollvariablen für shutdown und closesocket, es funktioniert aber auch bei mehr als 100 blocking-socket-threads auch mit grundsätzlich unzuverlässigen Proxies einwandfrei.

    Hat mich übrigens einige Versuche und Abstürze gekostet bis ich darauf gekommen bin. 😉



  • override schrieb:

    taurus schrieb:

    waitforsingleobject benutzt ich doch bei recv? wie soll das denn bei connect funktionieren? connect ist doch ein blocking element.. ?

    Nein, bei einem nonblocking socket kehrt connect sofort zurück.
    Nach dem Aufruf musst du dann iwie prüfen, ob eine Verbindung hergestellt wurde.

    Wenn das nicht über WFSO geht, kannst du den Socket Status über recv abfragen.

    Quatsch!
    connect kehrt eben nicht sofort zurück wenn es nicht sofort verbinden kann.

    Wer würde denn auch noch ein recv loslassen, wenn schon das connect scheitert?
    Mal ganz abgesehen davon, daß zwischen connect und recv nochwas erfolgreich passieren muß.



  • EOP schrieb:

    override schrieb:

    taurus schrieb:

    waitforsingleobject benutzt ich doch bei recv? wie soll das denn bei connect funktionieren? connect ist doch ein blocking element.. ?

    Nein, bei einem nonblocking socket kehrt connect sofort zurück.
    Nach dem Aufruf musst du dann iwie prüfen, ob eine Verbindung hergestellt wurde.

    Wenn das nicht über WFSO geht, kannst du den Socket Status über recv abfragen.

    Quatsch!
    connect kehrt eben nicht sofort zurück wenn es nicht sofort verbinden kann.

    Wer würde denn auch noch ein recv loslassen, wenn schon das connect scheitert?
    Mal ganz abgesehen davon, daß zwischen connect und recv nochwas erfolgreich passieren muß.

    Bevor du auf meinen Post antwortest, solltest du ihn auch lesen... Ich schrieb von NONBLOCKING sockets!

    "Until the connection attempt completes on a nonblocking socket, all subsequent calls to connect on the same socket will fail with the error code WSAEALREADY, and WSAEISCONN when the connection completes successfully."
    Quelle: http://msdn.microsoft.com/en-us/library/ms737625%28VS.85%29.aspx

    Was du zu recv gesagt hast, ist auch falsch! Wenn ein socket nicht verbunden ist, gibt GetLastError() nach einem (fehlgeschlagenen) recv WSAENOTCONN zurück.
    Damit kann man also doch prüfen, ob ein socket verbunden ist oder nicht, allerdings ist das nicht die empfohlene Methode.



  • Und um was geht's dem OP? Um blocking sockets. Sic!



  • EOP schrieb:

    Und um was geht's dem OP? Um blocking sockets. Sic!

    Achja, wo steht das denn?
    Er schrieb nur, dass er einen blocking connect ausführt, mehr nicht.
    Nach seiner Beschreibung wollte er einen Timeout für connect, was er mit nonblocking sockets problemlos machen kann.
    Abgesehen davon kann er danach wieder den socket auf blocking stellen.

    Ich verstehe echt nicht, wie man auf eine so dumme Art überheblich sein kann.



  • ach jetzt giftet euch doch nicht so an 😉

    Klar bricht connect irgendwann mal ab, aber mit Sicherheit nicht nach 15 Sek sondern viel, viel später.

    15 sek war nur angenommen.. in diesem fall nicht mal viel viel später... sondern gar nicht.. deswegen hab ich mich auch gewundert...

    das passiert wohl auch nur wenn der server überlastet ist.. (dsl modem also die ip ist ansich noch erreichbar)..

    das kann ich offensichtlich also nur durch einen non blocking socket lösen, oder?

    :schland: 😃 😃 😃 wir hätten eh gewonnen... ob 2:0 oder 4:0 was solls ^^



  • taurus schrieb:

    das kann ich offensichtlich also nur durch einen non blocking socket lösen, oder?

    Ja, allerdings kannst du wie gesagt nach dem (erfolgreichen) connect den socket wieder auf blocking stellen, wenn du das möchtest.



  • Nimm doch einfach select()



  • mhh.. ok ich nehme dann die non blocking variante.. werde ich aber erst nächste woche anfangen.. momentan gibts dafür keine zeit 🙂

    falls was ist melde ich mich nochmal..



  • so, ich hab die ganze sache jetzt mit select gelöst..

    problem jedoch: falls der server während select läuft wieder erreichbar ist, scheitert der verbindungsaufbau trotzdem.

    passiert wenn die dsl-leitung des servers überlastet ist...

    meine idee ist das ich die timeouts auf z.b. 10 oder 15sec setze und den connect mit select mehrmals hintereinander aufrufe...
    so bleibt er nicht hängen und wenn der server zwischendurch wieder erreichar ist funktioniert der verbindungsaufbau auch wieder und es gibt keinen failed to connect error...

    oder was meint ihr?

    dazu müsste ich ja folgenden block immer wieder nacheinander aufrufen(3 bis 4x (3,4 versuche von verbindungsaufbau))... aber geht das auch nicht simpler ?? d.h. das ich während select läuft den connect immer wieder "anstoße"?

    /* Den Verbindungsaufbau anstossen */
                if (connect(new_socket, (struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR)
                {
                   /* Das schlägt normalerweise fehl, wobei der Fehler WSAEWOULDBLOCK
                    * darauf hinweist, daß der Verbindungsaufbau durchaus noch Erfolgreich
                    * sein kann, und der Aufruf nur fehlgeschlagen ist, weil er andernfalls
                    * blockieren würde, was ja absichtlich deaktiviert wurde.
                    */
                   if (WSAGetLastError() != WSAEWOULDBLOCK)
                   {
                       std::stringstream ctd_tmp;
                       ctd_tmp << time(NULL) - t_start;
                       ctd_tmp >> con_timediff;
                       abbruch = "1, ";
    
                       connect_success = false;
                   }
                }
    
                /* Deskriptor-Set zurücksetzen und mit dem zu verbindenden Socket belegen */
                FD_ZERO(&fds);
                FD_SET(new_socket, &fds);
    
                /* Den gewählte timeout-Wert einsetzen */
                timeout.tv_sec = 240;
                timeout.tv_usec = 0;
    
                /* Nun select aufrufen; dieses kehrt entweder nach Ablauf des Timeouts
                 * zurück, oder wenn der Socket zum Schreiben bereit ist, was genau dann
                 * passiert, wenn er erfolgreich verbunden wurde.
                 */
                ret = select(new_socket + 1, NULL, &fds, NULL, &timeout);
                if (ret == SOCKET_ERROR)
                {
                    std::cout << "call to select failed: " << WSAGetLastError() << std::endl;
                   connect_success = false;
                }
    
                /* Falls select zurückgekehrt ist, aber der zu verbindende Socket nicht
                 * im Deskriptor-Set vorhanden ist, war das Verbinden in der gegebenen
                 * Zeit nicht erfolgreich.
                 */
                if (FD_ISSET(new_socket, &fds) == 0)
                {
    
                    std::stringstream ctd_tmp;
                    ctd_tmp << time(NULL) - t_start;
                    ctd_tmp >> con_timediff;
                    abbruch = abbruch + "2, ";
    
                    connect_success = false;
                }
    

Log in to reply