2017-06-21 3 views
-1

Also schreibe ich einen sehr einfachen TCP-Server, der nur die vom Client zurückgesendeten Nachrichten zurück zum Client sendet. Ich habe ein Setup, bei dem der Server in einer while-Schleife ausgeführt wird und entweder mit der Methode select() auf die Verbindung eines neuen Clients oder auf eine Nachricht von einem der vorhandenen Clients wartet. Meine Frage ist: Wie schließe ich von der Server-Seite den Master-Socket und im Grunde heruntergefahren den Server. Ich frage nicht nach genauem Code, sondern nach mehr Standardpraxis.Master-Socket vom Server schließen

Für einige Kontext: Auf lange Sicht stelle ich mir mehrere Clients vor, die mit meinem Server verbunden sind, und ich muss den Server anmutig von der Serverseite herunterfahren.

Noch mehr Kontext: Der Server-Code.

#define TRUE 1 
#define FALSE 0 
#define PORT 55555 

int main(int argc, char* argv[]) 
{ 
    int opt = TRUE; 
    int masterSocket, addrlen, newSocket, maxClients = 10, clientSockets[maxClients], 
     activity, valread, sd, maxSd; 
    struct sockaddr_in address; 
    char buffer[1025]; 

    fd_set readfds; 

    const char *message = "ECHO DAMON v1.0 \r\n"; 

    /* Initialize array with 0 so it's not read */ 
    for(int i = 0; i < maxClients ; i++) 
    { 
     clientSockets[i] = 0; 
    } 

    /* Create master socket */ 
    if((masterSocket = socket(AF_INET, SOCK_STREAM,0)) == 0) 
    { 
     perror("Error when trying to create master socket.\n"); 
     exit(EXIT_FAILURE); 
    } 

    /* Set master socket to allow multiple connections */ 
    if(setsockopt(masterSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) 
    { 
     perror("Could not set sockopt"); 
     exit(EXIT_FAILURE); 
    } 

    /* Socket type */ 
    address.sin_family = AF_INET; 
    address.sin_addr.s_addr = INADDR_ANY; 
    address.sin_port = htons(PORT); 

    if(bind(masterSocket, (struct sockaddr*)&address, sizeof(address)) < 0) 
    { 
     perror("Error, could not bind master socket. \n"); 
     exit(EXIT_FAILURE); 
    } 

    printf("Listening on %d. \n", PORT); 

    if(listen(masterSocket, 3) < 0) 
    { 
     perror("Error, could not listen.\n"); 
     exit(EXIT_FAILURE); 
    } 

    addrlen = sizeof(address); 
    puts("Waiting for connections...\n"); //just a printf variant 

    /* END INIT */ 

    while(TRUE) 
    { 
     /* Clear socket set */ 
     FD_ZERO(&readfds); 
     /* Add master socket to set */ 
     FD_SET(masterSocket, &readfds); 

     /* Add child sockets to set, will be 0 first iteration */ 
     for(int i = 0; i < maxClients ; i++) 
     { 
      sd = clientSockets[i]; // sd = socket descriptor 
      /* If valid socket descriptor */ 
      if(sd > 0) 
      { 
       FD_SET(sd, &readfds); 
      } 
      /* Get highest fd number, needed for the select function (later) */ 
      if(sd > maxSd) 
      { 
       maxSd = sd; 
      } 
     }//end for-loop 

     /* Wait for activity on any socket */ 
     activity = select(maxSd +1, &readfds, NULL, NULL, NULL); 

     if((activity < 0) && (errno != EINTR)) 
     { 
      printf("Error on select.\n"); //no need for exit. 
     } 

     /* If the bit for the file descriptor fd is set in the 
     file descriptor set pointed to by fdset */ 
     /* If something happend in the master socket, its a new connection */ 
     if(FD_ISSET(masterSocket, &readfds)) 
     { 
      if((newSocket = accept(masterSocket, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) 
      { 
       perror("Could not accept new socket.\n"); 
       exit(EXIT_FAILURE); 
      } 
      /* Print info about connector */ 
      printf("New connection, socket fd is %d, ip is: %s, port: %d\n", newSocket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); 

      if(send(newSocket, message, strlen(message), 0) != strlen(message)) 
      { 
       perror("Could not sent welcome message to new socket.\n"); 
      } 

      puts("Welcome message sen successfully.\n"); 

      /* Add new socket to array of clients */ 
      for(int i = 0; i < maxClients; i++) 
      { 
       if(clientSockets[i] == 0) 
       { 
        clientSockets[i] = newSocket; 
        printf("Adding socket to list of client at index %d\n", i); 
        break; 
       } 
      } 
     }//end masterSocket if 

     /* Else something happend at client side */ 
     for(int i = 0; i < maxClients; i++) 
     { 
      sd = clientSockets[i]; 

      if(FD_ISSET(sd, &readfds)) 
      { /* Read socket, if it was closing, else read value */ 
       if((valread = read(sd, buffer, 1024)) == 0) 
       { 
        getpeername(sd, (struct sockaddr*)&address, (socklen_t*)&addrlen); 
        printf("Host disconnected, ip %s, port %d.\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port)); 

        close(sd); 
        clientSockets[i] = 0; 
       } 
      } 
      else 
      { 
       buffer[valread] = '\0'; 
       send(sd, buffer, strlen(buffer), 0); 
      } 
     } 
    } 
    return 0; 
} 
+0

Was ist das Problem? Kann nicht beendet werden, weil das Programm auf dem 'select' blockiert ist oder wird dies nur nach Meinungen zu besten Praktiken abgefragt? – user4581301

+0

'close (masterSocket); Ausgang (0): "Unklar, was du fragst. – EJP

Antwort

1

Wenn Sie planen, Ihre Anwendung ordnungsgemäß zu beenden, indem eine break Anweisung in Ihrer Anwendung von etwas ähnlichen zu dieser Zugabe:

if (exit_condition) 
{ 
    break; 
} 

Sie diese Schlaufe am Ende Ihres Hauptes platzieren Funktion:

Wenn Sie dasselbe tun möchten, um einen Ausgang mit Ctrl-C zu behandeln, finden Sie Details wie Einrichten eines SIGINT-Handlers zur Handhabung von Ctr-C hier: Catch Ctrl-C in C. Platziere die obige Schleife in deinem Handler. Ihre sockelbezogenen Variablen müssen im globalen Gültigkeitsbereich deklariert werden, da Ihre Sockets nur von main() in Ihrem aktuellen Code sichtbar sind.