1

私は以下のサーバーコードを持っています.このコードのselect関数は、一部のクライアントがこれに接続しようとすると、エラーコード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 に答える