1

我在下面有这个服务器代码,当一些客户端尝试连接到这个时,这个代码中的选择函数会抛出一些错误的文件描述符错误以及错误代码 9,已经通过代码并且找不到任何问题,任何帮助将不胜感激,但这种行为并不是恒定的!

main()
{
    int server_fd, client_fd;
    socklen_t server_len, client_len;
    struct sockaddr_in server_address, client_address;
    fd_set readfds, testfds;
    char errorstr[128];
    char req_buf[REQ_BUF_LEN];
    int result;
    struct itimerspec time_period = {{10,0},{10,0}}; /* periodic timer */
    struct timeval sel_timeout = {0, 100000};
    int lines = 0;

    FD_ZERO(&readfds);
    FD_ZERO(&testfds);

    /* Create and name a socket for the server */
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if( server_fd < 0 ) {
        printf("socket creation failed \n");
        exit(0);
    }
    int on = 1;
    /* Enable address reuse */
    int ret = setsockopt( server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(BL_MANAGER_PORT);
    server_len = sizeof(server_address);

    result = bind(server_fd, (struct sockaddr *)&server_address, server_len);
    if( result < 0 ) {
        printf("Bind faield \n");
        exit(0);
    }

    /* Create a connection queue and wait for clients */
    result = listen(server_fd, MAX_CLIENTS);
    if( result < 0 ) {
        printf("Listen failed\n");
        exit(0);
    }

    FD_SET(server_fd, &readfds);

    /* create timer to fire every one second */
 int timer_fd  =  timerfd_create(CLOCK_MONOTONIC , 0);
    if( timer_fd < 0 ) {
        printf("Timer fd failed\n");
        exit(0);
    }

    result = timerfd_settime(timer_fd, 0, &time_period, NULL);
    if( result < 0 ) {
        printf("timer fd set time failed\n");
        exit(0);
    }
    FD_SET(timer_fd, &readfds);


    while(1) {
        int fd;
        int nread;
        int result;
        char *ptr;
        int len_read = 0;
        uint64_t expired = 0;

        testfds = readfds;

        result = select(FD_SETSIZE, &testfds, NULL, NULL, &sel_timeout);
        if( result < 0 ) {
           perror ("The following error occurred");
           printf("select failed");
           exit(0);
        }

        /* There is activity. Find the descriptor */
        for(fd = 0; fd < FD_SETSIZE; fd++) {
            if(FD_ISSET(fd, &testfds)) {
                if (fd == timer_fd) {
                        read(timer_fd, &expired, sizeof(uint64_t));
                        printf("rate = %d\n", (lines/(10 * (uint32_t)expired)));
                        lines = 0;
                } else if( fd == server_fd ) {         /* is this server fd? */
                    client_fd = accept(server_fd,
                                       (struct sockaddr *)&client_address,
                                       &client_len);
                    FD_SET(client_fd, &readfds);
                } else {                                 /* is this read fd? */
                    ioctl(fd, FIONREAD, &nread);
                    //assert(nread < REQ_BUF_LEN);
                    if( nread == 0 ) {
                        FD_CLR(fd, &readfds);
 close(fd);
                    } else {
                        nread = read(fd, req_buf, REQ_BUF_LEN-1);
                        //req_buf[nread] = '\0';
                        //printf("%s\n", req_buf);
                        ptr = req_buf;
                        while ((*ptr != EOF) && ++len_read < nread) {
                                if (*ptr == '\n') {
                                        ++lines;
                                }
                                ptr++;
                        }
                        //printf("num of lines: %d\n", lines);
                    }
                }
            } /* FD_ISSET(fd, &testfds)? */
        }
    } /* while(1) */
}
4

1 回答 1

0

你在滥用select(),所以你会从中得到随机结果。尝试更多类似的东西:

main()
{
    int server_fd, client_fd, max_fd = 0;
    socklen_t server_len, client_len;
    struct sockaddr_in server_address, client_address;
    fd_set readfds, testfds;
    char errorstr[128];
    char req_buf[REQ_BUF_LEN];
    int result;
    struct itimerspec time_period = {{10,0},{10,0}}; /* periodic timer */
    struct timeval sel_timeout;
    int lines = 0;

    FD_ZERO(&readfds);

    /* Create and name a socket for the server */
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if( server_fd < 0 ) {
        printf("socket creation failed \n");
        exit(0);
    }
    int on = 1;
    /* Enable address reuse */
    int ret = setsockopt( server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(BL_MANAGER_PORT);
    server_len = sizeof(server_address);

    result = bind(server_fd, (struct sockaddr *)&server_address, server_len);
    if( result < 0 ) {
        printf("Bind faield \n");
        exit(0);
    }

    /* Create a connection queue and wait for clients */
    result = listen(server_fd, MAX_CLIENTS);
    if( result < 0 ) {
        printf("Listen failed\n");
        exit(0);
    }

    FD_SET(server_fd, &readfds);
    max_fd = server_fd;

    /* create timer to fire every one second */
    int timer_fd  =  timerfd_create(CLOCK_MONOTONIC , 0);
    if( timer_fd < 0 ) {
        printf("Timer fd failed\n");
        exit(0);
    }

    result = timerfd_settime(timer_fd, 0, &time_period, NULL);
    if( result < 0 ) {
        printf("timer fd set time failed\n");
        exit(0);
    }

    FD_SET(timer_fd, &readfds);
    if (max_fd < timer_fd)
        max_fd = timer_fd;

    while(1) {
        int fd;
        int nread;
        int result;
        char *ptr;
        uint64_t expired = 0;

        FD_ZERO(&testfds);
        FD_COPY(&readfds, &testfds);

        sel_timeout.tv_sec = 0;
        sel_timeout.tv_usec = 100000;

        result = select(max_fd+1, &testfds, NULL, NULL, &sel_timeout);
        if( result < 0 ) {
           perror ("The following error occurred");
           printf("select failed");
           exit(0);
        }

        /* There is activity. Find the descriptor */
        for(fd = 0; fd <= max_fd; fd++) {
            if(FD_ISSET(fd, &testfds)) {
                if (fd == timer_fd) {
                    read(timer_fd, &expired, sizeof(uint64_t));
                    printf("rate = %d\n", (lines/(10 * (uint32_t)expired)));
                    lines = 0;
                } else if( fd == server_fd ) {         /* is this server fd? */
                    client_fd = accept(server_fd,
                                       (struct sockaddr *)&client_address,
                                       &client_len);
                    if (client_id < 0) {
                        perror ("The following error occurred");
                        printf("accept failed");
                    } else {
                        FD_SET(client_fd, &readfds);
                        if (max_fd < client_fd)
                            max_fd = client_fd;
                    }
                } else {                                 /* is this read fd? */
                    nread = read(fd, req_buf, REQ_BUF_LEN);
                    if( nread <= 0 ) {
                        FD_CLR(fd, &readfds);
                        close(fd);
                        if (fd == max_fd) {
                            max_fd = 0;
                            for (int fd2 = fd-1; fd2 >= 0; fd2--) {
                                if(FD_ISSET(fd2, &readfds)) {
                                    max_fd = fd2;
                                    break;
                                }
                            }
                        }
                    } else {
                        //printf("%.*s\n", nread, req_buf);
                        ptr = req_buf;
                        while ((nread > 0) && (*ptr != EOF)) {
                            if (*ptr == '\n') {
                                ++lines;
                            }
                            ptr++;
                            nread--;
                        }
                        //printf("num of lines: %d\n", lines);
                    }
                }
            } /* FD_ISSET(fd, &testfds)? */
        }
    } /* while(1) */
}

话虽如此,最好使用poll()epoll()在可用时,然后您根本不必处理fd_set

于 2013-03-14T00:41:37.647 回答