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 wolltestAlternativ 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 schonFazit:
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