2016-06-15 9 views
0

Ich schreibe ein TCP-Kommunikationsskript in C++, um zwischen meinem Computer und einem Aldebaran Nao-Roboter zu kommunizieren.TCP-Verbindung mit ungültigen Verbindungsblöcken Port

Im Allgemeinen funktioniert mein Skript. Das Problem, das ich habe, ist jedoch, dass wenn ich vom Client Verbindung anrufe (wenn die Server-Anwendung geschlossen oder die Ethernet-Verbindung entfernt wird), bekomme ich einen Fehler, dass die Operation läuft.

Sobald jedoch die Server-Anwendung neu gestartet/Ethernet-Kabel wieder verbunden ist, kann ich noch nicht verbinden, um eine Verbindung erfolgreich wiederherzustellen. Ich bekomme immer noch einen Fehler, dass die Operation ausgeführt wird.

Wenn mein Client feststellt, dass eine Verbindung nicht hergestellt werden kann, wird der Socket-Deskriptor vor dem erneuten Versuch einer Verbindung geschlossen. Hier ist mein Code für die Verbindung auf der Client-Seite:

Wenn es weitere Informationen gibt, die nützlich wären, würde ich gerne zur Verfügung stellen. Dieses Projekt ist relativ groß, daher wollte ich hier nicht zu viele irrelevante Informationen hinzufügen.

TCPStream* TCPConnector::connect(const char* serverIP, int port, int timeoutSec) 
{ 
    if (timeoutSec == 0) 
    { 
     return connect(serverIP, port); 
    } 

    struct sockaddr_in address; 

    // Store all zeros for address struct. 
    memset(&address, 0, sizeof(address)); 

    // Configure address struct. 
    address.sin_family = AF_INET; 
    address.sin_port = htons(port); // Convert from host to TCP network byte order. 
    inet_pton(PF_INET, serverIP, &(address.sin_addr)); // Convert IP address to network byte order. 

    // Create a socket. The socket signature is as follows: socket(int domain, int type, int protocol) 
    int sd = socket(AF_INET, SOCK_STREAM, 0); 

    int optval = 1; 

    if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) == -1) 
    { 
     std::cout << "failed to set socket option" << std::endl; 
    } 

    // Set socket to be non-blocking. 
    int arg; 
    arg = fcntl(sd, F_GETFL, NULL); 
    arg |= O_NONBLOCK; 
    fcntl(sd, F_SETFL, arg); 

    // Connect with time limit. 
    fd_set set; 
    FD_ZERO(&set); // Clear the set. 
    FD_SET(sd, &set); // Add our file descriptor to the set. 

    struct timeval timeout; 
    timeout.tv_sec = timeoutSec; 
    timeout.tv_usec = 0; 

    // If the connect call returns 0, then the connection was established. Otherwise, 
    // check if the three-way handshake is underway. 
    if (::connect(sd, (struct sockaddr *)&address, sizeof(address)) < 0) 
    { 
     // If the handshake is underway. 
     if (errno == EINPROGRESS) 
     { 
      std::cout << "handshake in progress" << std::endl; 

      // Designate timeout period. 
      int ret = select(sd + 1, NULL, &set, NULL, &timeout); 

      std::cout << "return value from select : " << ret << std::endl; 

      // Check if timeout or an error occurred. 
      if (ret <= 0) 
      { 
       return NULL; 
      } 
      else 
      { 
       // Check if select returned 1 due to an error. 
       int valopt; 
       socklen_t len = sizeof(int); 

       getsockopt(sd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &len); 

       if (valopt) 
       { 
        char * errorMessage = strerror(errno); // get string message from errn 
        std::string msg (errorMessage); 
        std::cout << msg << std::endl; 


        return NULL; 
       } 
      } 
     } 
     else 
     { 
      return NULL; 
     } 
    } 

    // Return socket to blocking mode 
    arg = fcntl(sd, F_GETFL, NULL); 
    arg &= (~O_NONBLOCK); 
    fcntl(sd, F_SETFL, arg); 

    // Create stream object. 
    return new TCPStream(sd, &address); 
} 
+0

Es blockiert den Port nicht. Ihr Code geht in eine Endlosschleife. – EJP

+0

@EJP Können Sie erklären, was die Endlosschleife verursacht? – Austin

Antwort

1

Ihr Socket ist nicht blockierenden Modus (Sie tun es explizit).

Als Ergebnis wird Ihre Verbindung sofort mit 'Verbindung ist in Bearbeitung' zurück. Wenn der Socket nicht blockierend ist, müssten Sie poll an diesem Socket verwenden und darauf warten, dass er lesbar und/oder schreibbar wird - dies würde bedeuten, dass die Verbindung erfolgreich oder nicht erfolgreich ist.

Eine bessere Option aus meiner Sicht wäre die Verwendung von blockierenden Sockets - ich sehe keinen Grund für Sie, nicht blockierende Anruf hier zu verwenden.

+0

Ich habe nicht blockierende Sockets eingebaut, so dass meine Client-Anwendung fortfahren konnte, auch wenn eine Verbindung nicht möglich war. Gleich nachdem ich den Socket als nicht blockierend eingestellt habe, benutze ich select, um nach einer bestimmten Zeitüberschreitung zu fragen. – Austin

+1

Richtiger Ansatz, vorausgesetzt, Sie schreiben nicht für Windows (verwenden Sie überlappende io), aber das wird Ihnen mit der Verbindung nicht helfen. Auf die eine oder andere Weise müssen Sie warten, bis die Verbindung abgeschlossen oder fehlgeschlagen ist, wie Sergey gesagt hat. Auf der anderen Seite sieht es so aus, als ob Sie in [dieselbe Richtung wie boost :: asio] gehen würden (http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio.html). Vielleicht lohnt es sich, mal reinzuschauen, bevor man zu viel Zeit verbringt, um das Rad neu zu erfinden. – user4581301

+0

@Austin, was ist der Sinn als? Sie warten immer noch auf das Verbindungsergebnis. Mach einfach eine blockierende Steckdose und erspare dir viele Sorgen. – SergeyA