【并发服务器系列】2 select模型

【并发服务器系列】2 select模型 - 邓维 - 博客园

【并发服务器系列】2 select模型

some of the codes are the same with previous article. I just list the different code here .

 chat_server.cpp

 

View Code 
复制代码
#include  " chat.h "

extern  int sock_server_init( int &listenfd , uint16_t server_port);
void err_quit( const  char *error_string)
{
    printf( " %s\n ", error_string);    
    exit( 1);
}
void err_sys( const  char *error_string)
{
    printf( " %s\n ", error_string);    
}

extern ssize_t p_read_from_p( int clientfd);
extern ssize_t p_write_to_p( int clientfd,  const  char *msg);
// #define WAIT_TIME_OUT
void sig_chld( int signo)
{
    pid_t pid;
     int stat;
     while( (pid = waitpid(- 1, &stat, WNOHANG)) >  0 )
    {
        printf( " client %d terminated \n ", pid);
    }
     return;
}
void chat_server()
{

     int listenfd, connfd;
    printf( " chat server start\n ");
     void sig_chld( int);
    pid_t childpid;
    socklen_t clilen;
     struct sockaddr_in cliaddr ;
    
     if(sock_server_init(listenfd,(uint16_t) SERVER_PORT) <  0)
    {        
         return ;
    }
    
    signal(SIGCHLD, sig_chld);
    
     char buf[ 200] = { 0};
    fd_set rset, allset;
     int maxfd, maxi, i, nready;
     int client[FD_SETSIZE], sockfd;
    ssize_t n_have_read;
    maxfd = listenfd;    
    maxi = - 1;
     for(i =  0; i < FD_SETSIZE; i++)
        client[i] = - 1;
    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);
#ifdef WAIT_TIME_OUT
     struct timeval timeout;
    timeout.tv_sec =  2;
    timeout.tv_usec =  500000;
#endif
     for( ; ; )
    {
        rset = allset ;
#ifdef WAIT_TIME_OUT
        nready =  select( maxfd + 1 , &rset , NULL, NULL, &timeout);
#else
        nready =  select( maxfd + 1 , &rset , NULL, NULL,  NULL);
#endif        
         if(nready ==  0)
        {
            printf( " select timeout\n ");
        }
         else  if(nready <   0)
        {
            perror( " select ");
        }    
         else
        {
             if(FD_ISSET(listenfd, &rset)) // new incoming connection
            {
                 int sleep_rand_sec = rand()% 4;
                printf( "   sleep %d   ", sleep_rand_sec);
                sleep(sleep_rand_sec);
                clilen =  sizeof(cliaddr);
                connfd = accept(listenfd, (SA*)&cliaddr, &clilen);
                printf( " incoming connection from IP: %s Port: %d\n "
                   inet_ntop(AF_INET, &cliaddr.sin_addr, buf,  sizeof(buf)), 
                   ntohs(cliaddr.sin_port));        

                 for(i=  0; i< FD_SETSIZE; i++)
                {
                     if(client[i] <  0)
                    {
                        client[i] = connfd; // save fd to empty pos
                         break;
                    }
                } // for
                 if(i == FD_SETSIZE)
                    err_quit( " too many clients ");
                
                FD_SET(connfd, &allset); // add new fd to set

                
// a few trick to avoid read all fdset
                 if(connfd >  maxfd) // compare to mark maxfd for select
                    maxfd = connfd;

                 if(i > maxi)  // mark max in client[] array
                    maxi = i;

                 if(--nready <=  0// no more fd to read , keep wait in accept
                     continue;


            } // if FD_SSSET
        }
         // usage of trick to avoid read all fdset
         for(i =  0; i <= maxi; i++)
        {
             if( (sockfd = client[i]) <  0)
                 continue; // this is not a ready one 

             if(FD_ISSET(sockfd, &rset))
            {
                 if(( n_have_read = p_read_from_p(sockfd ) ) ==  0)
                {
                     // connection closed by other end
                    printf( " close sock %d\n ", sockfd);
                    close(sockfd);
                    FD_CLR(sockfd, &allset);
                    client[i] = - 1;
                     // continue;
                }
                 else
                {
                     // printf("n_have_read = %d , client[%d] = %d \n", n_have_read, i, client[i]);
                    p_write_to_p(sockfd,  " hi , this is server ");
                }
                 if(--nready <=  0)
                     break; // no more readable fd to handle keep wait in accetp
            } // if FD_ISSET
        } // for

    } // for
复制代码

 

clientProcess.cpp

 

View Code 
#include  " chat.h "

ssize_t p_read_from_p( int clientfd)
{
     if( 0 == clientfd)
         return - 1;
        
    Message msg_receive;
    ssize_t read_size =  0; // fd read_size    
     if(( read_size = read(clientfd, &msg_receive.msg_head,  sizeof(msg_receive.msg_head))) <=  0)
    {
        perror( " read header ");
         return read_size; // connection closed by other end
    }

     if(( read_size += read(clientfd, &msg_receive.msg_content, msg_receive.msg_head.msg_length)) <=  0)
    {
        perror( " read msg ");
         return read_size; // connection closed by other end
    }

    printf( "  ----> receive msg_content:\t %s \n ", msg_receive.msg_content);
    fflush(stdout);
     return read_size;
}
ssize_t p_write_to_p( int clientfd,  const  char *msg)
{
    size_t slen = strlen(msg);
     if(slen > MAX_MSG_LENGTH ||  0 == slen)
         return - 1;
        
    Message msg_send;
    msg_send.msg_head.msg_length = slen;
    strncpy(msg_send.msg_content , msg, slen);
            
    ssize_t wn = write(clientfd, &msg_send , sizeof(msg_send.msg_head)+slen );
    printf( "  write finished msg:\t %s  \n ",msg );
     return wn;

 

 chat_client.cpp

 

View Code 
复制代码
#include  " chat.h "

extern  int sock_client_init( const  char*ipaddress, uint16_t server_port);

extern ssize_t p_write_to_p( int clientfd,  const  char *msg);
extern ssize_t p_read_from_p( int clientfd);
void chat_client( const  char* linkin_ip)
{
    printf( " chat client start %s \n ", linkin_ip);
     int clientfd = sock_client_init(linkin_ip, SERVER_PORT);    
     if(clientfd <  0 )
    {        
         return ;
    }
    ssize_t iw = p_write_to_p(clientfd,  " hello, this is client ");
    printf( "  iwrite =  %d \n ", iw);
    ssize_t ir = p_read_from_p(clientfd);
    printf( "  ireadback =  %d \n ", ir);
     if( ir ==  0)
        printf( "  connection close by server\n ");
复制代码

 

 

usage:

to start a server: ./chat
to start some clients:  ./chat localhost & ./chat localhost&./chat localhost & ./chat localhost &

Performance:Testing Machine: Local test ,OS: Fedora 14(Linux 2.6.35) 2 Cores:[email protected], Memory: 2GiB
Result: Handles 100~200 clients per sec

你可能感兴趣的:(select)