2017-06-21 45 views
-1

因此,我正在寫一個非常基本的TCP服務器,它只是回顯從客戶端發送回客戶端的消息。我有一個安裝程序,其中服務器在while循環中運行,並等待新客戶端連接或使用select()方法從其中一個現有客戶端發出消息。 我的問題是: 我如何從服務器端關閉主套接字並基本關閉服務器。我沒有要求確切的代碼,但更多的是標準的做法。從服務器端關閉主套接字

對於某些情況下: 從長遠來看,我想象多個客戶端連接到我的服務器,我需要從服務器端正常關閉服務器。

更多上下文:服務器代碼。

#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

問題是什麼?無法退出,因爲程序在'select'上被阻止,或者這是純粹輪詢最佳實踐的意見? – user4581301

+0

'close(masterSocket);退出(0);'不清楚你在問什麼。 – EJP

回答

1

如果您打算通過類似這個東西在您的應用程序添加break聲明優雅地退出你的應用程序:

if (exit_condition) 
{ 
    break; 
} 

你可以在你的主年底把這個循環功能:

/* close connections gracefully */ 
    closesocket(masterSocket); 
    masterSocket = 0;     /* optional, see comment below */ 
    for(int i = 0; i < maxClients; i++) 
    { 
     if (clientSockets[i] != 0) 
     { 
      shutdown(clientSockets[i]); 
      closesocket(clientSockets[i]); 
      clientSockets[i] = 0;  /* optional, except if you also have a SIGINT handler */ 
     } 
    } 

如果你想要做同樣的處理按Ctrl-C退出,你會發現怎麼細節設置一個SIGINT處理程序來處理Ctr-C: Catch Ctrl-C in C。然後將上面的循環放到你的處理程序中。你的套接字相關的變量必須在全局範圍內聲明,因爲你的套接字只能在當前代碼的main()中可見。

相關問題