Возвращаемое значение fcntl() с флагом F_GETFD?

Я использую fcntl() для дескриптора файла со следующим вызовом:

Retval = select(
    MaxSocketId + 1,
    &ReadSocketSet,
    (fd_set *)NULL,
    (fd_set *)NULL,
    (struct timeval *)NULL
);

if (Retval <= 0) {
    for (lIndexFD = 3; lIndexFD < (MaxSocketId + 1); lIndexFD++) {
        if ((lFlag = fcntl(lIndexFD, F_GETFD)) < 0) {
            if (errno == 9) {
                FD_CLR(lIndexFD, &ActiveSocketSet);
            }
        }
        else
            printf(" \n In fcntl Else cond %d ", lFlag);
    }
    continue;
}

Но мой процесс идет в бесконечном цикле в другом условии для fcntl() . Похоже, что fcntl() возвращает 0.

Я хотел бы знать, в каком состоянии он возвращает 0 и что делать, чтобы справиться с этой ситуацией.


person arjun gaur    schedule 30.10.2018    source источник


Ответы (1)


ОБНОВИТЬ:

if (Retval <= 0) может измениться на if (Retval < 0).

Когда Retval равно нулю, select работает нормально.

Когда Retval равно -1, а errno равно EBADF, используйте fcntl для проверки fd.

Вы смотрели, как fcntl всегда возвращает 0, потому что:

  1. Не установлены флаги FD_CLOEXEC fd

  2. select не сбой, и fcntl тоже не сбой, потому что все fd действительны.


fcntl есть много видов cmd. При использовании F_GETFD это означает получение флагов файлового дескриптора.

Посмотрите руководство fcntl, в этом типе есть только один флаг (FD_CLOEXEC). Поэтому, если не установить этот флаг для fd, то F_GETFD вернет значение 0.

Флаги дескриптора файла

Следующие команды управляют флагами, связанными с файловым дескриптором. В настоящее время определен только один такой флаг: FD_CLOEXEC, флаг закрытия при выполнении. Если бит FD_CLOEXEC равен 0, файловый дескриптор останется открытым в execve(2), в противном случае он будет закрыт.

  F_GETFD (void)
         Read the file descriptor flags; arg is ignored.

  F_SETFD (int)
         Set the file descriptor flags to the value specified by arg.

Когда он не вернет 0?

  1. Когда open один файл, флаг FD_CLOEXEC по умолчанию отключен. Вы можете включить это так.

    fd = open(filepath, O_RDONLY | O_CLOEXEC)
    
  2. Вызовите fcntl(fd, F_SETFD, FD_CLOEXEC), чтобы включить флаг FD_CLOEXEC.

person randomeval    schedule 30.10.2018
comment
могу ли я очистить этот fd от fd_set, если fcntl() возвращает ‹=0? Потому что после этого мне нужно вызвать accept() для sock fd. Итак, если этот флаг не установлен, я должен очистить fd? - person arjun gaur; 30.10.2018
comment
также, почему он отключен в этом случае? потому что здесь я не открываю ни один файл. Я вызываю bind(), затем listen() на sock fd, а затем select(), чтобы проверить, готов ли он принимать соединения. - person arjun gaur; 30.10.2018
comment
Нет, я имею в виду, когда fcntl() возвращает значение =0 для fd, должен ли я очистить этот fd из моего fd_set с помощью FD_CLR, как я делаю в случае errno=9 (EBADF) - person arjun gaur; 30.10.2018
comment
Для функции socket будет то же самое, по умолчанию FD_CLOEXEC отключена. Вы можете включить его следующим образом. socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0), Или в accept4 функция accept4(fd, addr, len, SOCK_CLOEXEC). Используйте команду man socket и аналогично проверьте руководство. - person randomeval; 30.10.2018
comment
@arjungaur Теперь я понимаю. Когда errno=9, вам нужно очистить его. В вашем случае речь идет не о установке или получении F_CLOEXEC, он просто проверяет, действительно ли fd, когда выбор не выполнен. - person randomeval; 30.10.2018
comment
да, изначально я не использовал fcntl(), но мой процесс зациклился с errno=9, поэтому я справился с этим, очистив этот плохой fd через FD_CLR. Но теперь снова зацикливается, так как fcntl() возвращает 0 - person arjun gaur; 30.10.2018
comment
@arjungaur Используйте if (Retval <0) и fcntl для обработки ошибки выбора. Используйте, если (Retval == 0) дескриптор не имеет данных. - person randomeval; 30.10.2018
comment
хорошо, но в этом случае будет выбран возврат 0? Потому что, если бы я указал интервал тайм-аута, он будет блокироваться только до этого интервала и возвращать 0, если fd не готов. Но здесь tmeout равен NULL , на странице руководства говорится, что в этом случае select будет блокироваться на неопределенный срок. Поэтому select должен возвращать только >1 (fd готов) или ‹1 (ошибка не установлена) - person arjun gaur; 30.10.2018
comment
@arjungaur Так есть ли код, установленный для сокета fd в неблокируемый? И функция select может возвращать -1 с ошибкой другого типа, например EINTR. Есть ли шанс получить эту ошибку? - person randomeval; 30.10.2018
comment
Нет, у меня нет, поэтому по умолчанию он блокируется. - person arjun gaur; 30.10.2018
comment
Давайте продолжим обсуждение в чате. - person arjun gaur; 30.10.2018