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 brauchenHallo,
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