How come when a thread exits the parent process also exits? When I run the server all is well. It sits and listens on the socket. When a client connects the server threads to serve it. When they talk back and forth the client exits and the server quits as well. I"m using pthread.h for the threading. Here they are!
First the client:
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#define CLIENT_CONNECTED 0
#define CLIENT_NOT_CONNECTED 1
#define PORT 9999
#define MAX_CLIENTS 100
using namespace std;
struct client {
int socket;
int state;
pthread_t tid;
};
int
connectToServer (char *address )
{
struct hostent *hostinfo;
struct sockaddr_in name;
int s;
int rc = 0;
if ( ( s = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
{
cerr<<"Client could not declare socket"<<"\n";
exit( 1 );
}
name.sin_family = AF_INET;
name.sin_port = htons ( ( unsigned short int ) PORT );
name.sin_addr.s_addr = htonl( INADDR_ANY );
hostinfo = gethostbyname ( address );
if ( hostinfo == NULL )
{
cerr<<"Host unknown"<<"\n";
exit( 1 );
}
name.sin_addr = *( struct in_addr * ) hostinfo->h_addr;
if ( connect( s, ( const sockaddr * ) &name, sizeof( name ) ) < 0 )
{
cerr<<"Could not connect to host"<<"\n";
exit( 1 );
}
else
{
/* if( fcntl( s, F_SETFL, O_NONBLOCK ) == -1 )
{
perror( "fcntl" );
exit( 1 );
} */
char readbuf[1024];
char message[ ] = "START";
rc = send( s, message, strlen(message), 0 );
cout<<"RC on send() was "<<rc<<"\n";
if ( rc > 0 )
{
cout<<"using recv...\n";
while( ( rc = recv( s, readbuf, 1, 0 ) ) > 0 )
{
readbuf[ rc ] = '\0';
cout<<"Server responds with: "<<readbuf<<"\n";
}
return true;
}
else
{
return false;
}
}
}
void
killsignal( int param )
{
fprintf( stderr, "Disconnecting." );
exit( 1 );
}
int
main ( )
{
signal( SIGKILL, killsignal );
signal( SIGINT, killsignal );
char address[] = "localhost";
connectToServer( address );
}
And the server:
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#define CLIENT_CONNECTED 0
#define CLIENT_NOT_CONNECTED 1
#define PORT 9999
#define MAX_CLIENTS 100
using namespace std;
struct client {
int socket;
int state;
pthread_t tid;
};
int
sendClient( char *message, int *socket )
{
int rc = 0;
cout<<message<<"\n";
rc = send( *socket, message, strlen(message), 0 );
cout<<"send RC is: "<<rc<<"\n";
}
void
strtochrstr( char **to, string from )
{
int len = from.size( );
*to = ( char * )malloc( ( len + 1 ) * sizeof( char ) );
if ( to == NULL ){
cout<<"out of memory!\n";
exit( 1 );
}
*to[ 0 ] = '\0';
strcpy( *to, from.c_str( ) );
}
int
createSocket ( int *s )
{
struct sockaddr_in name;
if ( ( *s = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
{
cerr<<"Server: Socket"<<"\n";
}
name.sin_family = AF_INET;
name.sin_port = htons( (unsigned short int) PORT );
name.sin_addr.s_addr = htonl( INADDR_ANY );
if ( bind( *s, ( struct sockaddr * ) &name, sizeof( name ) ) < 0 )
{
cerr<<"Could not bind to socket."<<"\n";
exit( 1 );
}
return *s;
}
void *
serveClient( void *clientState )
{
int c;
int rc = 0;
char readbuf[ 2 ];
char message[ ] = "Message to client";//( char * ) malloc( 300 * sizeof( char ) );
struct client *mystate = ( struct client * ) clientState;
/* Set socket tot NONBLOCKING */
if( fcntl( mystate->socket , F_SETFL, O_NONBLOCK ) == -1 )
{
perror( "fcntl" );
exit( 1 );
}
while ( true )
{
while ( ( rc = recv( mystate->socket, readbuf, 1 , 0 ) ) > 0 )
{
readbuf[ 1 ] = '\0';
cout<<readbuf<<"\n";
}
sendClient( message, &( mystate->socket ) );
}
}
int
listenUp ( int *s )
{
int i = 0;
int error = 0;
pthread_t clientIds[MAX_CLIENTS];
struct client clients[MAX_CLIENTS];
struct sockaddr_in fsaun[MAX_CLIENTS];
int fromlen[MAX_CLIENTS];
while ( i++ < MAX_CLIENTS )
clients[i].state = CLIENT_NOT_CONNECTED;
if ( listen( *s, 10 ) < 0 )
{
cerr<<"Could not listen on socket"<<"\n";
exit( 1 );
}
while ( true )
{
while ( ( clients[i++].state == CLIENT_CONNECTED && i < MAX_CLIENTS ) );
if ( ( clients[i].socket = accept(
*s,
( sockaddr * ) &fsaun[i],
( socklen_t * ) &fromlen[i] ) ) < 0 )
{
cerr<<"Could not accept connection "<<i<<"\n";
}
else
{
error = pthread_create(
&clients[i].tid,
NULL,
serveClient,
(void *)&clients[i]
);
}
i = 0;
}
}
void
killsignal( int param )
{
fprintf( stderr, "Disconnecting.\n" );
}
void
intsignal( int param )
{
fprintf( stderr, "Write error.\n" );
}
int
main ( )
{
signal( SIGKILL, killsignal );
signal( SIGINT, intsignal );
int mySock = createSocket( &mySock );
listenUp( &mySock );
}
Your server is continously sending data to the client. When your client exits, it hasn't read all the data there is to read on the socket.
This condition will generate a TCP RST, the default behavior on *nixes when a TCP RST is received is to deliver the SIGPIPE signal to the process. The default behavior of the SIGPIPE signal is to exit the program.
For TCP servers its common to just ignore the SIGPIPE signal, with SIGPIPE ignored write()/send() will return an error when the mentioned condition(a client exits or closes a socket with pending data) and set errno to EPIPE
Add this in main() of your server:
signal(SIGPIPE,SIG_IGN);
Some more info can be found here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With