Я использую 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;
}
Но мой процесс выполняется в бесконечном цикле в условии else для fcntl (). Похоже, что fcntl () возвращает 0.
Я хотел бы знать, в каком состоянии он возвращает 0 и что делать, чтобы справиться с этой ситуацией.
ОБНОВИТЬ:
if (Retval <= 0)
может измениться на if (Retval < 0)
.
Когда Retval
равен нулю, select
работает нормально.
Когда Retval
равен -1, а errno - EBADF
, тогда используйте fcntl check fd is valid.
Вы смотрели fcntl, он всегда возвращает 0, потому что:
Не установлены флаги FD_CLOEXEC
fd
select
не сбой, и fcntl тоже не сбой, потому что все fd действительны.
fcntl
имеют много видов cmd
. При использовании F_GETFD
это означает получение флагов дескриптора файла.
Обратитесь к руководству fcntl
, в этом типе есть только один флаг (FD_CLOEXEC). Таким образом, если не установить этот флаг для fd, то F_GETFD
вернет значение 0.
File descriptor flags
The following commands manipulate the flags associated with a file descriptor. Currently, only one such flag is defined: FD_CLOEXEC, the close-on-exec flag. If the FD_CLOEXEC bit is 0, the file descriptor will remain open across an execve(2), otherwise it will be closed.
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?
Когда open
один файл, флаг FD_CLOEXEC
по умолчанию отключен. Вы можете включить это так.
fd = open(filepath, O_RDONLY | O_CLOEXEC)
Вызовите fcntl(fd, F_SETFD, FD_CLOEXEC)
, чтобы включить флаг FD_CLOEXEC
.
также, почему он отключен в этом случае? потому что здесь я не открываю никаких файлов. Я вызываю bind (), за которым следует listen () для sock fd, а затем select (), чтобы проверить, готов ли он принимать соединения.
Нет, я имею в виду, когда fcntl () возвращает значение = 0 для fd, должен ли я очистить этот fd из моего fd_set с помощью FD_CLR, как я делаю в случае errno = 9 (EBADF)
Для функции socket
будет то же самое, по умолчанию FD_CLOEXEC
отключен. Вы можете включить его вот так. socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)
, либо в accept4
функция accept4(fd, addr, len, SOCK_CLOEXEC)
. Используйте команду man socket
и аналогичным образом проверьте руководство.
@arjungaur Теперь я понимаю. Когда errno=9
, то нужно его очистить. В вашем случае речь идет не о том, чтобы установить или получить F_CLOEXEC
, а просто проверить, действительно ли fd, когда выбор не удался.
да, изначально я не использовал fcntl (), но мой процесс зашел в бесконечный цикл с errno = 9, поэтому я обработал его, очистив этот плохой fd через FD_CLR. Но теперь он снова переходит в цикл, поскольку fcntl () возвращает 0
@arjungaur Используйте if (Retval <0)
и fcntl
для обработки ошибки выбора. Используйте, если дескриптор (Retval == 0)
не содержит данных.
хорошо, но в этом случае будет выбран возврат 0? Потому что, если бы я указал интервал тайм-аута, он будет блокироваться только до этого интервала и вернет 0, если fd не готов. Но здесь tmeout имеет значение NULL, на странице руководства говорится, что в этом случае select будет блокироваться на неопределенное время. Таким образом, select должен возвращать только> 1 (fd готов) или <1 (устанавливается errno)
@arjungaur Значит, установил код socket fd на неблокирующий? И функция select может возвращать -1 с ошибкой другого типа, например EINTR
. Есть шанс получить эту ошибку?
Нет, по умолчанию он блокируется.
Позвольте нам продолжить обсуждение в чате.
Могу ли я удалить этот fd из fd_set, если fcntl () возвращает <= 0? Потому что после этого мне нужно вызвать accept () на sock fd. Итак, если этот флаг не установлен, я должен очистить fd?