Как работает FD_ISSET и что не так в моем коде - PullRequest
0 голосов
/ 14 марта 2020

У меня есть некоторая путаница по поводу того, как сокет fd и fd_set изменились на FD_ISSET и как FD_ISSET может проверить это сокет fd , включая fd_set . Итак, я сделал небольшой тест.

    int sock_fd = -1;
    fd_set read_set;
    while (sock_fd < 20)
    {
        printf("Init:           sock_fd is %d, read_set is %ld\n", sock_fd, read_set);
        FD_ZERO(&read_set);
        printf("after FD_ZERO   sock_fd is %d, read_set is %ld\n", sock_fd, read_set);
        FD_SET(sock_fd, &read_set);
        printf("after FD_SET    sock_fd is %d, read_set is %ld\n", sock_fd, read_set);
        FD_ISSET(sock_fd, &read_set);
        printf("after FD_ISSET  sock_fd is %d, read_set is %ld\n", sock_fd, read_set);
        FD_CLR(sock_fd, &read_set);
        printf("after FD_CLR    sock_fd is %d, read_set is %ld\n", sock_fd, read_set);
        printf("***********************************\n");
        sock_fd++;
    }

Это мой код. Регулярность очевидна. Для каждой пары значение read_set является значением sock_fd + 63, то есть read_set = sock_fd + 63 . Исходя из этого, я могу сказать, что исходное значение read_set составляет 63 (111111) . Но я не знаю почему. Итак, я решил сделать следующий тест. Я добавил немного printf в мою прошлую демонстрацию. Это часть этого кода.

 fd_set read_set;
    fd_set write_set;
    fd_set select_read_set;


    FD_ZERO(&read_set);
    FD_ZERO(&write_set);
    FD_ZERO(&select_read_set);
    printf("after FD_ZERO, read_set is %ld, write_set is %ld, select is %ld\n", read_set, write_set, select_read_set);
    for (i = 0; i < MAX_CLIENT_NUM; i++)
    {
        client_fd[i] = -1;
    } 

    memset(&serv_addr, 0, sizeof(serv_addr));
    memset(&cli_addr, 0, sizeof(cli_addr));

     printf("111 sock_fd is %d, read_set is %ld, write_set is %ld, select is %ld\n", read_set, write_set, select_read_set);
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    printf("sock_fd is %d\n", sock_fd);
    if (sock_fd < 0)
    {
        perror("Fail to socket");
        exit(1);
    }


    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERVER_PORT);
    serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    printf("222 sock_fd is %d, read_set is %ld, write_set is %ld, select is %ld\n", read_set, write_set, select_read_set);

    unsigned int value = 1;
    if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&value, sizeof(value)) < 0)
    {
        perror("Fail to setsockopt");
        exit(1);
    }

     printf("333 sock_fd is %d, read_set is %ld, write_set is %ld, select is %ld\n", read_set, write_set, select_read_set);
    serv_addr_len = sizeof(serv_addr);
    if (bind(sock_fd, (struct sockaddr*)&serv_addr, serv_addr_len) < 0)
    {
        perror("Fail to bind");
        exit(1);
    }
    if (listen(sock_fd, BACK_LOG) < 0)
    {
        perror("Fail to listen");
        exit(1);
    }

    char buf[1024];
    //max_fd = sock_fd;
    printf("PPP sock_fd is %d, read_set is %ld, write_set is %ld, select is %ld\n", read_set, write_set, select_read_set);
    FD_SET(sock_fd, &read_set);
    printf("QQQ sock_fd is %d, read_set is %ld, write_set is %ld, select is %ld\n", read_set, write_set, select_read_set);

Результат меня совершенно смущает. Это приговор напечатан на экране.

after FD_ZERO, read_set is 31834128, write_set is 0, select is 0
111 sock_fd is -404688640, read_set is 16, write_set is 2147483583, select is 0
sock_fd is 3
222 sock_fd is 0, read_set is 140083558421840, write_set is -104, select is 1844674407370955161
333 sock_fd is 1, read_set is 2, write_set is 140083557848394, select is 4
PPP sock_fd is 20, read_set is 16, write_set is 140083557847575, select is 0
QQQ sock_fd is 0, read_set is 8, write_set is 3, select is 0

Я не могу их понять. Посмотрите мой код, я ничего не делал для read_set после FD_ZERO до FD_SET, но read_set всегда менялся. И даже я никогда ничего не делаю для write_set , select_read_set эти два fd_set, они изменились. Я понятия не имею об этих четырех вопросах: 1. Как FD_ISSET оценивает fd , содержащиеся в fd_set ? 2. Для этих двух тестов, почему результат их? Я описал свое замешательство. 3. Что касается второго теста, вы можете видеть, что значение 'sock_fd' также может быть изменено. Я думаю, это должно быть изменено bind() и другими функциями. Но я не понимаю, почему сокет fd нужно изменить? Исходя из моих мыслей, один сокет fd уникален для сокета, и этот будет сохраняться до закрытия. 4. Является ли возвращаемое значение socket() (сокет fd) случайным? Я не могу найти какую-то регулярность этого.

Пожалуйста, научите меня или дайте мне несколько советов. Спасибо

1 Ответ

0 голосов
/ 14 марта 2020

В вашем первом фрагменте кода у вас есть:

int sock_fd = -1;
... // stuff that doesn't modify sock_fd
FD_SET(sock_fd, &read_set);

.... но POSIX говорит (выделение добавлено)

Поведение этих макросов не определено, если аргумент fd меньше 0 или больше или равен FD_SETSIZE, или если fd не является допустимым дескриптором файла, или если какой-либо из аргументов является выражением с побочными эффектами.

Таким образом, вы делаете что-то явно вызванное как неопределенное, что означает, что компилятор и система свободны делать что-либо в ответ.

Вы также относитесь к read_set, как к long int, что это не должно быть, и когда это не так, также вызывает неопределенное поведение, потому что спецификатор printf() не соответствует соответствующему аргументу. Вы делаете это тоже во втором блоке кода. Кроме того, у вас есть вызовы printf(), в которых количество спецификаторов формата не совпадает с количеством аргументов, что также является неопределенным поведением.

Таким образом, в основном, путем разрыва контракта с языком и API функций, например вы не можете ожидать каких-либо последовательных или логических результатов.

Ваш компилятор должен предупреждать вас по крайней мере о проблемах с printf(). Вы не активируете предупреждения (-Wall -Wextra для g cc или лязг)? Не делать это - огромная ошибка в C программировании.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...