使用epoll来做为两个client socket的中转站

发布于 2022-09-07 19:56:59 字数 9279 浏览 13 评论 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 :

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心如狂蝶 2022-09-14 19:56:59

read failed的原因是因为异步引起,返回了EAGAIN, 需要对它做特殊处理

read message的原因还没找到

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文