1

Trying to limit the amount of client connections in my client-server c application. This is what I have, however it doesn't work. (Doesn't even recognise when max_connections is reached. How can I fix this?

int main(int argc, char *argv[])
{
        //fill db
        if (obtainDb() == false) {
                printf("Database obtain error.\n");
                exit(true);
        }
        //initialise variables
        total_connections = 0;

        /* generate the socket */
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
                perror("socket");
                exit(true);
        }

        /* generate the end point */
        my_addr.sin_family = AF_INET;         // host byte order
        my_addr.sin_port = htons(MYPORT);     // short, network byte order
        my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP

        /* bind the socket to the end point */
        if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
        == -1) {
                perror("bind");
                exit(true);
        }

        /* start listnening */
        if (listen(sockfd, BACKLOG) == -1) {
                perror("listen");
                exit(true);
        }

        printf("server starts listnening ...\n");

        while(true){
                sin_size = sizeof(struct sockaddr_in);

                if (total_connections == max_connections) {
                        printf("Max Number of clients connected!\n");
                        while(total_connections == max_connections);
                }

                if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
                &sin_size)) == -1) {
                        perror("accept");
                        continue;
                }
                total_connections++;
                printf("server: got connection from %s\n", \
                        inet_ntoa(their_addr.sin_addr));

                userInput();

                while(waitpid(-1,NULL,WNOHANG)>0);

        }

        return false;

}

Thanks

Edit: UserInput():

void userInput(void) {
if (!fork()) { // this is the child process
    while(true){
        char buffer[MAXDATASIZE];
        char res[MAXDATASIZE];

        memset(buffer, '\0', MAXDATASIZE);
            memset(res, '\0', sizeof(res));

        if ((numbytes=recv(new_fd, buffer, sizeof(buffer), 0)) == -1) {
            perror("recv");
            exit(true);
        }
        if (numbytes == 0) {
            printf("client left");
            close(new_fd);
            total_connections--;
            exit(false);
        }
        buffer[numbytes] = '\0'; // add null terminator
        printf("Request: %s\n",buffer);
        search(buffer,res);
    }
    close(new_fd);  // parent doesn't need this
    exit(false);
}
close(new_fd);

}

alk
  • 69,737
  • 10
  • 105
  • 255
Grace O'Brien
  • 121
  • 1
  • 10
  • 3
    Why `waitpid` when your not `fork`ing anywhere? – Gopi Krishna Oct 17 '13 at 07:27
  • `while(total_connections == max_connections);` isn't that undefined behavior, or at least the compiler can assume that the loop will terminate. It could remove the loop. Or transform it to `if(total_connections == max_connections) while(1);` – usr Oct 17 '13 at 07:31
  • @usr in a single-threaded process that loop will hang when the condition is true. – Klas Lindbäck Oct 17 '13 at 07:32
  • @KlasLindbäck the C standard does not recognize the existence of threads. There is indeed a rule that loop termination can be assumed (under certain conditions which are met here). Also, as I have shown, the transform to `if-while(1)` is valid. – usr Oct 17 '13 at 07:33
  • @GopiKrishna: I bet the **real** code `fork()`s away a child and the latter increases the connection counter, which though would always become `1` for each and every connection and never gets increased in the parent code doing the test against the allowed maximum. – alk Oct 17 '13 at 07:34
  • In any case you should certainly sleep for 100ms or so while there are too many connections, instead of trying to smoke the CPU. – user207421 Oct 17 '13 at 07:35
  • Always post "the real code", that is the code you can use to reproduce the issue your are asking about. – alk Oct 17 '13 at 07:36
  • @alk That might be the case. – Gopi Krishna Oct 17 '13 at 07:44
  • @alk I posted the fork() code – Grace O'Brien Oct 17 '13 at 07:46
  • @usr I tried your suggestion and it didn't change – Grace O'Brien Oct 17 '13 at 07:47

2 Answers2

2

When you fork all variables are copied to the new process. That means that the children have their own copy of total_connections.

Instead of using a variable, you should use wait to find out whether any children have exited.

Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
  • Can you please elaborate? – Grace O'Brien Oct 17 '13 at 07:52
  • What you are trying to do is fairly complex and you need to set up a signal handler to wait for the children (so that your parent can focus on listening for new connections). Last time I did this I was a fledgling socket programmer and it took me a couple of weeks to make it work. – Klas Lindbäck Oct 17 '13 at 08:06
  • OK, that seems a bit out of my understanding, would you reccomend a similar way to limit client connections to 30? – Grace O'Brien Oct 17 '13 at 08:09
  • Yes. The parent needs to be notified when a child exits. You could use other forms of inter-process communication, but the advantage of using `wait` is that the OS kernel will notify the parent even if the child exits unnaturally. You should discuss the problem with your architect/professor/tech lead. – Klas Lindbäck Oct 17 '13 at 09:06
  • Another way is to `do it all single-threaded in the same process and use `select` to wait for client input and new connections at the same time. Using `select` in a single thread is easier in my opinion. Example: http://www.binarytides.com/multiple-socket-connections-fdset-select-linux/ – Klas Lindbäck Oct 17 '13 at 13:21
1

Forking creates a new instance of your proces, which also means that each variable is copied to the new process. Your initial total_connections will actually never get increased beyond 1.

C fork dealing with global variable

A relatively simple option would be to use threads instead of processes for handling multiple clients simultaneously.

Community
  • 1
  • 1
Dariusz
  • 21,561
  • 9
  • 74
  • 114