I wrote a simple server in C. It answers connections on port 8888. It works great…until I try to run it as a background process.
When I run it like
$ ./server
And then attempt to connect with a client it works fine. When I attempt to run it like:
$ ./server &
Or if I run it like
$ ./server
And then detach it with CTRL+z and attempt to connect with a client I get
Connection Refused
Has anyone encountered this problem before? I would greatly appreciate a solution.
Here is the code surrounding the accept( ) call as requested:
char remoteIP[ INET6_ADDRSTRLEN ];
int yes=1; /* for setsockopt() SO_REUSEADDR, below */
int i, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO( &master ); /* clear the master and temp sets */
FD_ZERO( &read_fds );
/* get us a socket and bind it */
memset( &hints, 0, sizeof hints );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ( ( rv = getaddrinfo( NULL, URL_PORT, &hints, &ai ) ) != 0 )
{
/* fprintf( stderr, "selectserver: %s\n", gai_strerror( rv ) ); */
exit( 1 );
}
/* printf( "Listening on port %s for URLs...\n", URL_PORT ); */
for( p = ai; p != NULL; p = p->ai_next )
{
listener = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
if ( listener < 0 )
{
continue;
}
/* lose the pesky "address already in use" error message */
setsockopt( listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof( int ) );
if ( bind( listener, p->ai_addr, p->ai_addrlen) < 0 )
{
close( listener );
continue;
}
break;
}
/* if we got here, it means we didn't get bound */
if ( p == NULL )
{
/* fprintf( stderr, "selectserver: failed to bind\n" ); */
exit( 2 );
}
freeaddrinfo( ai ); /* all done with this */
/* listen */
if ( listen( listener, 10 ) == -1 )
{
perror( "listen" );
exit( 3 );
}
/* add the listener to the master set */
FD_SET( listener, &master );
/* keep track of the biggest file descriptor */
fdmax = listener; /* so far, it's this one */
/* main loop */
for( ; ; ) {
for( i = 0; i <= fdmax; i++ )
{
if ( SOCKETS[ i ].in_progress )
{
if ( pthread_join( SOCKETS[ i ].thread, NULL ) != 0 )
{
/* fprintf( stderr, "Error terminating thread %i\n", i ); */
}
else
{
SOCKETS[ i ].in_progress = FALSE;
}
}
}
read_fds = master; /* copy it */
if ( select( fdmax + 1, &read_fds, NULL, NULL, NULL ) == -1 )
{
perror( "select" );
exit(4);
}
/* run through the existing connections looking for data to read */
for( i = 0; i <= fdmax; i++ ) {
if ( FD_ISSET( i, &read_fds ) && SOCKETS[ i ].in_progress == FALSE )
{
/* we got one!! */
if ( i == listener )
{
/* handle new connections */
addrlen = sizeof remoteaddr;
newfd = accept( listener, ( struct sockaddr * ) &remoteaddr, &addrlen );
if ( newfd == -1 )
{
perror( "accept" );
}
else
{
FD_SET( newfd, &master ); /* add to master set */
if ( newfd > fdmax )
{ /* keep track of the max */
fdmax = newfd;
}
/*
printf(
"selectserver: new connection from %s on socket %d\n",
inet_ntop( remoteaddr.ss_family, get_in_addr( ( struct sockaddr* ) &remoteaddr ), remoteIP, INET6_ADDRSTRLEN ), newfd );
*/
}
}
Your process reads from or writes to its controlling terminal and hence is stopped by SIGTTIN or SIGTTOU when you run it in the background with
&.Relevant excerpt from the bash manpage:
The sending of SIGTTOU is controlled by a flag which is off by default, so your problem is likely caused by reading from the controlling terminal. If you want to prevent background processes from writing to the terminal (i.e. re-enable the sending of SIGTTOU to processes attempting a background write), use this command:
You can revert back to the default behavior with:
When you press Ctrl+Z you cause SIGTSTP to be sent to the process. Default disposition of this signal is also to stop the process. If you wish to make the process continue running in the background, use this command:
Note that the job number may be different in your case. Check using the
jobcommand.Note that unlike SIGSTOP these three signals can be handled or ignored by your process if you dislike the behavior. The read/write system calls will then return EINTR instead of blocking.