0
while (((connfd = accept(listenfd)) != -1){
    if (fork() == 0) {
        write(connfd, buffer ,strlen(buffer));
        close(connfd);
    }
}

Hi all, I got a sample question for an exam at OS. Let's say I have a TCP server which handles multiple clients, using the above code. As specified in the question, the rest of the code should be valid. Now, each time a client connects to this server, it reads data from it and then gets stuck. The correct answer to the question is that it happens because the server doesn't close the connection with the client properly.

I'm not sure if I get it completely, isn't

close(socket)

enough? As far as I'm concerned, when a socket is closed by one side, the other side reads EOF and returns 0. Considering the client gets stuck while reading, it shouldn't get to that EOF and move on?

Dan
  • 21
  • 3

2 Answers2

1

fork() will return 0 in the child process and a positive pid in the parent process. Therefore the close(connfd); will be invoked only in the child process.

However, the parent process did the accept and it still holds an open file descriptor to the socket. It too needs to close it. The socket will not be shut down until all opened file descriptors are closed. That is to say, you need something like

pid_t child_pid = fork();
if (child_pid == 0) {
    write(connfd, buffer ,strlen(buffer));
    close(connfd);
}
else if (child_pid > 0) {
    // parent
    close(connfd);
}
else {
    // a fork error occurred, handle and remember to close(connfd)
}
0

An addition to @AnttiHaapala's answer.

You should not close a socket immediately after sending something on it. Write returns as soon as the data has been queued and the close could actually occur before everything has been sent.

The foolproof way is to use a graceful shutdown:

pid_t child_pid = fork();
if (child_pid == 0) {
    write(connfd, buffer ,strlen(buffer));
    shutdown(connfd, SD_SEND);              // send an EOF condition
    while (read(connfd, buffer, sizeof(buffer) > 0);  // wait for the peer to close its side
    close(connfd);          // and actually close
}
else if (child_pid > 0) {
    // parent
    close(connfd);          // direct close because no send is pending
}
else {
    // a fork error occurred, handle and remember to close(connfd)
}
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252