Nicht-blockierende Sockets: select() oder fcntl()



  • Welche Methode nimmt man am besten? Oder braucht man eine Kombination von beiden? Ich habe beide probiert und mit beiden fehlerhaftes Verhalten gekriegt:

    - Ursprünglich wollte ich einfach mit select() arbeiten, aber in mind. einem Fall blockiert read() dann trotzdem.

    - Deshalb habe ich die Sockets zusätzlich mit fcntl() als nicht-blockierend eingestellt. Aber damit wartet das connect() offenbar nicht lange genug, so dass der Verbindungsaufbau zu einem Server nicht gleich funktioniert (Errno: Operation now in progress). Nach kurzer Zeit geht die Verbindung dann trotzdem.

    Mit select() + Zeitangabe kann ich dagegen einfach lange genug warten, wenn ich fcntl() nicht verwende.

    InetSocket::InetSocket()
    {
        m_fdSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);  
        if(-1 == m_fdSocket ) /* ... */
    
        // diese drei Zeilen hab ich wegen dem blockierenden read() hinzugefuegt
        int flags;
        if ((flags = fcntl(m_fdSocket, F_GETFL, 0)) < 0) /* ... */
        if (fcntl(m_fdSocket, F_SETFL, flags | O_NONBLOCK) < 0) /* ... */
    
        m_destAddr.sin_family = AF_INET;  
        m_destAddr.sin_port = 0;  
        m_destAddr.sin_addr.s_addr = 0; 
    }
    
    int InetSocket::recvData(char* buffP, int CntP)
    {
        fd_set rfds;
        struct timeval tv;
    
        int iRet;
        ssize_t iReadRet;
    
        /* Watch m_fdSocket to see whether it will block */
        FD_ZERO(&rfds);
        FD_SET(m_fdSocket, &rfds);
        /* Wait up to one second. */
        tv.tv_sec = 1;
        tv.tv_usec = 0;
    
        iRet = select(m_fdSocket+1, &rfds, NULL, NULL, &tv);
    
        if (iRet < 0)        
            iRet = -1;
        else
        {
            iReadRet = read(m_fdSocket, buffP, CntP);
    
            if( -1 == iReadRet )
               iRet = -1;
            else
                iRet = static_cast<int>(iReadRet);
        }
    
        return iRet; // returns -1 on error, otherwise number of bytes read
    }
    

    Hab ich irgendeinen Fehler drin den ich nicht erkenne?

    Vielen Dank!



  • als anmerkung:
    mit NONBLOCK
    1. connect() -> EINPROGRESS: des ist kein fehler; der tcp handshake braucht immer lange 🙂
    2. mit select() auf write warten -> connect() war erfolgreich bzw. es gibt nen Fehler wie Host down ua. Die Daten di du senden willst dann einfach mit send() abschicken und den fehler auswerten, bei retval > 1 war der Verbindungsaufbau erfolgreich, sonst ist in retval halt der Fehlercode enthalte (Host down, no net ua)
    3. normal mit select() auf read warten -> so wie du es wolltest

    Alternativ ohne NONBLOCK:
    mit getsockopt() und SO_RCVBUF die anstehenden Bytes auslesen und nur die bei recv() als parameter übergeben; wenn in der zwischenzeit wieder neue bytes angekommen sind, sagt dir das select() beim nächsten mal schon 😉

    Fazit:
    Mit NONBLOCK sind auch connect()s ohne 'Wartezeit' während ohne haste gleich ne Antwort ob geklappt hat, der nachfolgende Kram ist mehr Geschmacksache/Religion/ua. Teste einfach beides und nimm was die mehr zusagt.



  • Könntest du mal den link zum tutorial für fcntl geben? thx


Anmelden zum Antworten