账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    使用epoll来做为两个client socket的中转站
    38
    0

    问题描述

    我建立一个socket server, 当有其他client连接时,如果一开始输入key123, 那么就认为它是主client, 监视它的in和out, 如果连接后输入的不是key123, 那么就是从client, 从client可以有多个

    从client输入的字符都会被server转发到主client, 主client输入的字符会被群发到所有从client

    如果telnet 127.0.0.1 2323这样的手工方法,没有问题,

    但如果我用C写个程序来模拟手工输入,那么主client很快后读失败,而且server的状态不如预期

    问题出现的环境背景及自己尝试过哪些方法

    我尝试过用nonblocking,也不行

    相关代码

    // 请把代码文本粘贴到下方(请勿用图片代替代码)

    socket server

    
    
    static void handle_accept(int epollfd, int listenfd, cli_t * pclient)
    {
        int clifd;
        struct sockaddr_in cliaddr;
        pclient->cliaddr = &cliaddr;
    
        socklen_t  cliaddrlen = sizeof(*(pclient->cliaddr));
        clifd = accept(listenfd,(sockaddr*)(pclient->cliaddr),&cliaddrlen);
        if (clifd == -1)
        {
            if ( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) {
                return;
            } else {
                perror("accpet error:");
            }
        } else {
            report_peer_connected((pclient->cliaddr), cliaddrlen);
            set_socket_non_blocking(clifd);
            add_event(epollfd,clifd,EPOLLIN|EPOLLOUT);
            // add one client read event
            int nread, nwrite;
    #if 0
            const char * req = "please input the key:\n";
            printf("size: %d\n", sizeof(req));
            while ((nwrite = write(clifd,req,strlen(req)))<0)
            {
                if(nwrite == -1){
                    if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                        //sleep(1);
                        continue;
                    } else {
                        perror("read error");
                        exit(1);
                    }
                }
            }
    #endif
            int times=0;
    //        sleep(3);
            memset(ibuf, 0, sizeof(buf_t));
    
            //while (((nread = read(clifd,ibuf->buf,MAXSIZE))<0) && (times < 100))
            while (((nread = read(clifd,ibuf->buf,MAXSIZE))<0))
            {
                if(nread == -1){
                    if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
    //                    usleep(100000);
                        times++;
                        continue;
                    } else {
                        perror("read error");
                        exit(1);
                    }
                }
            }
            if (nread == 0) {
                fprintf(stderr, "nread: the client closed\n");
            } else {
                printf("nread: %d, ibuf->buf: %s\n", nread, ibuf->buf);
                if((strncmp(ibuf->buf , "key123", 6) == 0))
                {
    #ifdef DEBUG
                    printf("get HW connection\n");
    #endif
                    pclient->hwfd = clifd;
                    pclient->hwcon = 1;
                } else {
    #ifdef DEBUG
                    printf("get SW connection\n");
    #endif
                    pclient->swfd.push_back(clifd);
                    (pclient->swconnum)++;
                    delete_event(epollfd,clifd,EPOLLIN);
                }
            }
        }
    }
    
    // HW side reads message from the client
    static void do_read(int epollfd, int fd, cli_t * pclient)
    {
        if((fd == pclient->hwfd)) //if it's hw side
        {
            memset(ibuf, 0, sizeof(buf_t));
            int nread;
            nread = read(fd,ibuf->buf,MAXSIZE);
            if (nread == -1)
            {
                perror("read error:");
                close(fd);
                delete_event(epollfd,fd,EPOLLIN);
            }
            else if (nread == 0)
            {
                fprintf(stderr,"client %s:%d close.\n", inet_ntoa(pclient->cliaddr->sin_addr), ntohs(pclient->cliaddr->sin_port));
                close(fd);
                delete_event(epollfd,fd,EPOLLIN);
            }
            else
            {
                // get message from HW side
                {
    #ifdef DEBUG
                    printf("read message from hw is : %s\n",ibuf->buf);
    #endif
                }
                int nwrite;
                for(int i=0; i<(pclient->swconnum);i++)
                {
                    nwrite = write((pclient->swfd[i]),ibuf->buf,nread);
                }
                //modify_event(epollfd,fd,EPOLLIN|EPOLLOUT);
            }
        }     
    }
    
    // HW side writes message to the client
    static void do_write(int epollfd,int fd, cli_t * pclient)
    {
        if((fd == pclient->hwfd)) //if it's hw side
        {
            int nwrite;
            int nread;
            char towrite[MAXSIZE];
            for(int i=0;i<((pclient->swfd).size());i++)
            {
                set_socket_non_blocking((pclient->swfd[i]));
                nread=read((pclient->swfd[i]), obuf->buf, MAXSIZE);
                if((nread == -1) && ((errno == EAGAIN || errno == EWOULDBLOCK)))
                {
                } else {
                    if(nread == -1)
                    {
                        perror("read error:");
                        pclient->swfd.erase((pclient->swfd).begin()+i);
                        pclient->swconnum--;
                    } else {
                        if(nread == 0)
                        {
                            fprintf(stderr, "client closed.\n");
                            close(pclient->swfd[i]);
                            pclient->swfd.erase((pclient->swfd).begin()+i);
                            pclient->swconnum--;
                        } else {
    
    #ifdef DEBUG
                            printf("write message to hw is : %s\n", obuf->buf);
    #endif
                            nwrite=write(fd, obuf->buf, nread);
                        }
                    }
                }
            }
            //modify_event(epollfd,fd,EPOLLIN);
                
        }
    }
    
    static void handle_events(int epollfd, int listenfd, struct epoll_event * events, int num, cli_t* pclient, TRANSTATE * ts )
    {
        int i;
        int fd;
        struct sockaddr_in cliaddr;
        //*ts = INIT;
        // wark over the event ready
        for (i = 0;i < num;i++)
        {
            fd = events[i].data.fd;
            // deal as to different event
            if ((fd == listenfd) &&(events[i].events & EPOLLIN))
            {
                handle_accept(epollfd, listenfd, pclient);
            } else {
                if (events[i].events & EPOLLIN)
                {
                    do_read(epollfd, fd, pclient);
                } else {
                    if (events[i].events & EPOLLOUT)
                    {
                        do_write(epollfd,fd,pclient);
                    }
                }
            }
        }
    }
    
    static void do_epoll(int listenfd)
    {
        //                int epollfd;
        struct epoll_event events[EPOLLEVENTS];
        cli_t * pclient = (cli_t*)malloc(sizeof(cli_t));
    
        set_socket_non_blocking(listenfd);
    
        int ret;
        // create one epoll fd
        int epollfd = epoll_create(FDSIZE);
        TRANSTATE ts=INIT;
        // add one listen fd into epoll pool
        add_event(epollfd,listenfd,EPOLLIN);
        for ( ; ; )
        {
            // get the event ready
            ret = epoll_wait(epollfd,events,EPOLLEVENTS,EPOLL_TIMEOUT);
            if(ret <0) {
                perror("epoll_wait failed");
                exit(1);
            } else if (ret == 0) {
                fprintf(stderr, "no socket ready for read within %d secs\n", EPOLL_TIMEOUT/1000);
            } else {
                handle_events(epollfd,listenfd,events,ret,pclient,&ts);
            }
        }
        close(epollfd);
    }
    

    master client

    
    
        char message[BUF_SIZE];
    
        int nread, nwrite;
        int times = 0;
    
        const char * key="key123\n";
        printf("key len=%d\n", strlen(key));
    
    #if 1
        while ((nwrite = write(sock,key,strlen(key)+1))<0)
        {
            if(nwrite == -1){
                if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                    //sleep(1);
                    printf("nwrite: try again!\n");
                    continue;
                } else {
                    perror("read error");
                    exit(1);
                }
            }
        }
    #endif
    //    nwrite = write(sock,key,strlen(key)+1);
        if (nwrite == 0) {
            fprintf(stderr, "nwrite: the client closed\n");
    //        exit(1);
        } else {
                printf("HW connected\n");
        }
        
        //keep communicating with server
        int count = 0;
        while(1)
        {
            sprintf(message, "%d\n", count++);
            
            //Send count
            printf("[Send]: %s", message);
            if( (nwrite=write(sock, message, strlen(message)+1)) < 0)
            {
                perror("write failed");
                exit(1);
            } else {
                if( nwrite == 0)
                {
                    printf("nwwrite: no message written to svr\n");
                } else {
                    printf("writen done\n");
                }
            }
    #if 1
            //Receive a reply from the server
            while( (nread =read(sock, message, BUF_SIZE)) <= 0)
            {
                if(nread <0)
                {
                    perror("read failed");
                    exit(1);
                } else {
                    printf("nread: 0\n");
                    continue;
                }
            }
    
            
            printf("[Recv]: %s\n", message);
    #endif
            usleep(CLIENT_INTERVAL);
        }
        
        close(sock);
        exit(0);
    }

    先运行./go

    然后在另一个窗口运行./to

    你期待的结果是什么?实际看到的错误信息又是什么?

    我期待可以看到./to一直运行, 然后它发出去的0, 1, 2, 3... 会被socket server接收到

    一旦有其他client (telnet 127.0.0.1 2323, 然后随便输入字符回车), 那么主client的消息会被发到从client, 从client的消息会被发到主client

    实际上./to在read的时候就会出错

    read failed: Resource temporarily unavailable

    而在socket server侧没有收到主client发过来的数字“0”, 而是一个空字符(0)

    read message from hw is :

    0
    打赏
    收藏
    点击回答
        全部回答
    • 0
    更多回答
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部