LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Socket program and fork() (https://www.linuxquestions.org/questions/programming-9/socket-program-and-fork-4175496115/)

Jerry Mcguire 02-25-2014 02:29 AM

Socket program and fork()
 
Hi, I'm puzzled with the piece of code. It is a TCP server program that is supposed to handle multiple incoming connections. First I tried without FORKING and the outcome was expected: When the function some_connection_handler() exits, the client knows immediately about the disconnection.

But when I tried with FORKING, and when some_connection_handler() exited, the client didn't know. What is wrong?

Error checking skipped for easier reading..
Code:

// ...

//Create socket
int servSock = socket( PF_INET, SOCK_STREAM, 0 );

//Set non-blocking
int n = fcntl( servSock, F_GETFL );
fcntl( servSock, F_SETFL, n | O_NONBLOCK );

//Set socket options
int opt = 1;
setsockopt( servSock, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt) );
setsockopt( servSock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt) );

//Fill in the address of the server ip and port
struct sockaddr_in servAddr;
memset( &servAddr, 0, sizeof(servAddr) );
// ... some details skipped ...
servAddr.sin_family = AF_INET;

bind( servSock, (struct sockaddr *)&servAddr, sizeof(servAddr) );
listen( servSock, SOMAXCONN );

fd_set rfds;
struct timeval tv;
int retval;

tv.tv_sec = 0;
tv.tv_usec = 100;

while (1) {
        FD_ZERO(&rfds);
        FD_SET(servSock, &rfds);
        retval = select( servSock+1, &rfds, NULL, NULL, &tv );
        if (retval == -1) {
                perror("select()");
                break;
        }
        else if (retval && FD_ISSET(servSock, &rfds)) {

                int clntSock = accept( servSock, (struct sockaddr *)NULL, NULL );

#ifdef FORKING
                pid_t pid = fork();
                if (pid == -1) {
                        perror( "fork()" );
                        break;
                }
                else if (pid == 0) {
                        some_connection_handler( clntSock );
                        close( clntSock );
                        break;
                }
#else
                some_connection_handler( clntSock );
                close( clntSock );
#endif
        }
        else {
                if (some_quit_condition()) break;
        }
}//while(1)
close( servSock );

//...


pan64 02-25-2014 02:44 AM

I think you need to check the return code of the child process.
Code:

if ( pid == -1 ) # error case
if ( pid == 0 ) # child process
if ( pid > 0 ) # parent process
# missing
{ wait for pid }
# see man wait


Jerry Mcguire 02-25-2014 03:11 AM

I think I found the answer - both the parent and child instance should close the clntSock, as:
Code:

#ifdef FORKING
                pid_t pid = fork();
                if (pid == -1) {
                        perror( "fork()" );
                        break;
                }
                else if (pid == 0) {
                        some_connection_handler( clntSock );
                        close( clntSock );
                        break;
                }
                else {
                        close( clntSock );  // could write this block of if-code better.
                }
#else
                some_connection_handler( clntSock );
                close( clntSock );
#endif

will look up wait. Thanks.

Jerry Mcguire 02-25-2014 09:42 PM

To make this post complete for future readers, I have revised the code to:
Code:

//Create socket
int servSock = socket( PF_INET, SOCK_STREAM, 0 );

//Set non-blocking
int n = fcntl( servSock, F_GETFL );
fcntl( servSock, F_SETFL, n | O_NONBLOCK );

//Set socket options
int opt = 1;
setsockopt( servSock, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt) );
setsockopt( servSock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt) );

//Fill in the address of the server ip and port
struct sockaddr_in servAddr;
memset( &servAddr, 0, sizeof(servAddr) );
// ... some details skipped ...
servAddr.sin_family = AF_INET;

bind( servSock, (struct sockaddr *)&servAddr, sizeof(servAddr) );
listen( servSock, SOMAXCONN );

fd_set rfds;
struct timeval tv;
int retval;

tv.tv_sec = 0;
tv.tv_usec = 100;

while (1) {
        FD_ZERO(&rfds);
        FD_SET(servSock, &rfds);
        retval = select( servSock+1, &rfds, NULL, NULL, &tv );
        if (retval == -1) {
                perror( "select()" );
                break;
        }
        else if (retval && FD_ISSET(servSock, &rfds)) {

                int clntSock = accept( servSock, (struct sockaddr *)NULL, NULL );

                pid_t pid = fork();
                if (pid == -1) {
                        perror( "fork()" );
                        break;
                }
                else if (pid == 0) {
                        some_connection_handler( clntSock );
                        close( clntSock );
                        break;
                }
                else {
                        close( clntSock );
                }
        }
        else {
                if (some_quit_condition()) break;
        }
        waitpid( -1, NULL, WNOHANG );
}//while(1)
waitpid( -1, NULL, 0 ); // or wait( NULL )
close( servSock );



All times are GMT -5. The time now is 04:20 AM.