-1

So I'm writing a very basic TCP server which just echoes back the messages sent from the client back to the client. I have a setup where the server is running in a while loop and waiting for either a new client to connect or for a message from one of the existing clients using the select() method. My question is: How do i, from the server side, close the master socket and basically shutting down the server. Im not asking for exact code but more for standard practice.

For some context: In the long run I am imagining multiple clients connected to my server and I need to shutdown the server gracefully from the server side.

Even more context: The 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;
}

1 Answers1

1

If you are planning to exit your application gracefully by adding a breakstatement in your app by something similar to this:

if (exit_condition)
{
    break;
}

You can place this loop at the end of your main function:

  /* 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 */
        }
    }

If you want to do the same to handle an exit with Ctrl-C, you will find details on how to setup a SIGINT handler to handle Ctr-C here: Catch Ctrl-C in C. Place the above loop in your handler, then. Your sockets-related variables will have to be declared at global scope, since your sockets are only visible from main() in your current code.

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19