为什么我的客户端会杀死我的服务器

时间:2011-03-05 22:15:25

标签: c++ c sockets pthreads client

如果线程退出父进程也会退出?当我运行服务器一切都很好。它坐在并听取套接字。当客户端连接服务器线程以提供服务时。当他们来回交谈时,客户端会退出,服务器也会退出。我正在使用pthread.h进行线程处理。他们来了!

首先是客户:

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

服务器:

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

3 个答案:

答案 0 :(得分:6)

您的服务器不断向客户端发送数据。 当您的客户端退出时,它还没有读取套接字上要读取的所有数据。

此条件将生成TCP RST,当接收到TCP RST时,* nixes上的默认行为是将SIGPIPE信号传递给进程。 SIGPIPE信号的默认行为是退出程序。

对于TCP服务器,它常见于忽略SIGPIPE信号,忽略SIGPIPE write()/ send()将在上述条件(客户端退出或关闭具有挂起数据的套接字)时返回错误并将errno设置为EPIPE

在服务器的main()中添加:

signal(SIGPIPE,SIG_IGN);

可以找到更多信息here

答案 1 :(得分:3)

exit终止进程,包括您在同一进程中生成的所有线程。你应该从你的线程函数返回而不调用exit。

答案 2 :(得分:2)

exit()杀死整个进程,这会杀死构成它的所有线程。你可以互换地使用“线程”和“过程”这两个词,这表明你们两人之间可能会有一些混淆。

多个线程可以在单个进程中执行,但如果进程终止,则所有线程都会死掉。