connect(), select(), getsockopt(): auch ohne Listen-Port "erfolgreich"



  • ⚠
    edit: Ich habe in einer connectTo()-Version mit gesockopt() gerade einen Fehler gefunden und teste eine verbesserte Version, bis dahin bitte diesen Thread ignorieren...

    Stephan

    ⚠
    edit die 2.
    Sorry für den überflüssigen Thread...Ich glaube ich habe die Methode jetzt soweit korrigiert dass sie funktioniert. Ist unten angehängt, vielleicht kann's jemand brauchen

    Hallo,

    ich verwende für TCP/IP-Sockets eine Klassenmethode für den Verbindungsaufbau, die so aussieht:

    int InetClientSocket::connectTo() const
    {
        int iRet = -1;
        int res;
        int flags;
    
        // set socket non-blocking
        if( (flags = fcntl(m_fdSocket, F_GETFL, 0)) < 0 )
            exit(-1);
        flags |= O_NONBLOCK;
        if( fcntl(m_fdSocket, F_SETFL, flags) < 0 )
            exit(-1);
    
        do
        {
            errno = 0;
            res = connect(m_fdSocket, (struct sockaddr*)&m_destAddr, sizeof(struct sockaddr_in)) ;
        }
        while( EINTR == errno );
    
        if(res < 0)
        {
            if(EINPROGRESS == errno)
            {
                struct timeval timeout = m_ConnectTimeout; 
                fd_set wfds;                // write file descr set
                FD_ZERO(&wfds);             // Watch m_fdSocket 
                FD_SET(m_fdSocket, &wfds);
    
                do
                {
                    errno = 0;
                    res = select(m_fdSocket+1, NULL, &wfds, NULL, &timeout);
                }
                while( EINTR == errno );
    
                if(FD_ISSET(m_fdSocket, &wfds)) // socket selected for write // connection successful
                    iRet = 0;   // hier lande ich auch wenn nichts erreichbar ist
                else 
                    exit(-1);
            }
            else 
                exit(-1);
        }
    
        // set socket blocking again
        flags &= ~O_NONBLOCK;
        if( fcntl(m_fdSocket, F_SETFL, flags) < 0 )
            exit(-1);
    
        return iRet;
    }
    

    Aber auch wenn mit den verwendeten IP/Port-Einstellungen weder ein Listen-Port noch ein Rechner erreichbar sind, gibt mir diese Funktion "0" (erfolgreicher Verbindungsaufbau) zurück. Die Fehler tauchen dann erst bei read() / write()-Funktionen auf den Socket auf.

    Liegt das daran dass ich in den Socket-Buffer schreiben kann, auch wenn keine Gegenstelle vorhanden ist? Sollte ich dann im select() den Socket vielleicht besser auf "lesbar" prüfen?

    Sieht jemand wo der Fehler liegt?

    Stephan



  • Hier die mit getsockopt() verbesserte connectTo()-Methode, die bei mir funktioniert:

    int InetClientSocket::connectTo() const
    {
        int iRet = -1;
        int res;
        int flags;
    
        // set socket non-blocking
        if( (flags = fcntl(m_fdSocket, F_GETFL, 0)) < 0 )
            exit(-1);
        flags |= O_NONBLOCK;
        if( fcntl(m_fdSocket, F_SETFL, flags) < 0 )
            exit(-1);
    
        do
        {
            errno = 0;
            res = connect(m_fdSocket, (struct sockaddr*)&m_destAddr, sizeof(struct sockaddr_in)) ;
        }
        while( EINTR == errno );
    
        if(res < 0)
        {
            if(EINPROGRESS == errno)
            {
                struct timeval timeout = m_ConnectTimeout; 
                fd_set wfds;                // write file descr set
                FD_ZERO(&wfds);             // Watch m_fdSocket 
                FD_SET(m_fdSocket, &wfds);
    
                do
                {
                    errno = 0;
                    res = select(m_fdSocket+1, NULL, &wfds, NULL, &timeout);
                }
                while( EINTR == errno );
    
                if(FD_ISSET(m_fdSocket, &wfds)) // socket selected for write // connection successful
                {
                    // hier landet man offenbar IMMER, auch wenn kein Rechner oder LISTEN-Port erreichbar ist
    
    // Socket mit "getsockopt()" pruefen! siehe "man 2 connect"
                    int so_err;
                    socklen_t lon = sizeof(so_err);
                    res = getsockopt(m_fdSocket, SOL_SOCKET, SO_ERROR, (void*)(&so_err), &lon);
    
                    if(res < 0) // error
                        exit(-1);
                    else    // check so_err
                    {
                        if(so_err == 0) // success
                            iRet = 0;
                        else
                            exit(-1);
                    }
                }
                else 
                    exit(-1);
            }
            else // (errno != EINPROGRESS) -> connect didn't work
                exit(-1);
        }
    
        // set socket blocking again
        flags &= ~O_NONBLOCK;
        if( fcntl(m_fdSocket, F_SETFL, flags) < 0 )
            cout << "error" << endl;
    
        return iRet;
    }
    

    Viel Spaß damit, Stephan


Anmelden zum Antworten