3 votes

Pourquoi mon client tue-t-il mon serveur ?

Comment se fait-il que lorsqu'un thread se termine, le processus parent se termine également ? Lorsque je lance le serveur, tout va bien. Il est assis et écoute sur le socket. Lorsqu'un client se connecte, le serveur s'exécute pour le servir. Lorsqu'ils discutent, le client quitte le processus et le serveur quitte également le processus. J'utilise pthread.h pour le threading. Les voici !

D'abord le 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 );
}

Et le serveur :

#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 );
}

8voto

nos Points 102226

Votre serveur envoie continuellement des données au client. Lorsque votre client quitte le serveur, il n'a pas lu toutes les données qu'il y a à lire sur la socket.

Cette condition génère un TCP RST, le comportement par défaut sur les *nixes lorsqu'un TCP RST est reçu est de délivrer le signal SIGPIPE au processus. Le comportement par défaut du signal SIGPIPE est de quitter le programme.

Pour les serveurs TCP, il est courant d'ignorer le signal SIGPIPE. Si SIGPIPE est ignoré, write()/send() renverra une erreur lorsque la condition mentionnée (un client quitte ou ferme une socket avec des données en attente) et mettra errno à EPIPE.

Ajoutez ceci dans la fonction main() de votre serveur :

signal(SIGPIPE,SIG_IGN);

Quelques informations supplémentaires sont disponibles aquí

3voto

eznme Points 13158

exit met fin au processus, y compris à tous les threads que vous avez créés à l'intérieur de ce même processus. Vous devriez simplement revenir de vos fonctions de threads sans appeler exit.

2voto

Jack Kelly Points 9640

exit() tue le processus complet qui va tuer tous les fils qui le composent. Vous utilisez les mots "fil" et "processus" de manière interchangeable, ce qui suggère qu'il pourrait y avoir une certaine confusion entre les deux dans votre esprit.

Plusieurs threads peuvent s'exécuter au sein d'un même processus, mais si le processus meurt, tous ses threads meurent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X