【并发服务器系列】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:E3200@2.4GHz, Memory: 2GiB
Result: Handles 100~200 clients per sec

原文地址:https://www.cnblogs.com/no7dw/p/2680620.html