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

  • 相关阅读:
    Lua ip转整数
    纯lua实现Base64加密与解密
    lua之base64的解码和编码(三种方案实现)
    Lua 5.1 位操作(与,或,异或操作)
    Lua打印Table对象
    Lua 截取字符串(截取utf-8格式字符串)
    lua 截取字符,以及取字符个数(非字符串长度)
    lua 加密解密
    Openwrt与贝壳物联平台通讯示例
    php socket编程:使用socket_recv而不是socket_read
  • 原文地址:https://www.cnblogs.com/lexus/p/2870690.html
Copyright © 2011-2022 走看看