que node c network-programming unix sockets

node - E/S sin bloqueo UNIX: O_NONBLOCK vs. FIONBIO



browserify vs webpack (3)

Antes de la estandarización había ioctl( ... FIONBIO ... ) y fcntl( ... O_NDELAY ... ) , pero estos se comportaban de forma inconsistente entre los sistemas, e incluso dentro del mismo sistema. Por ejemplo, era común que FIONBIO trabajara en sockets y O_NDELAY que trabajara en ttys, con mucha inconsistencia para cosas como pipes, fifos y dispositivos. Y si no sabía qué tipo de descriptor de archivos tenía, tendría que establecer ambos para estar seguro. Pero además, una lectura no bloqueante sin datos disponibles también se indicó de forma inconsistente; dependiendo del SO y del tipo de descriptor de archivo, la lectura puede devolver 0, o -1 con errno EAGAIN, o -1 con errno EWOULDBLOCK. Incluso hoy, configurar FIONBIO u O_NDELAY en Solaris causa una lectura sin datos para devolver 0 en un tty o pipe, o -1 con errno EAGAIN en un socket. Sin embargo, 0 es ambiguo ya que también se devuelve para EOF.

POSIX abordó esto con la introducción de O_NONBLOCK , que tiene un comportamiento estandarizado en diferentes sistemas y tipos de descriptores de archivos. Debido a que los sistemas existentes generalmente quieren evitar cualquier cambio en el comportamiento que pueda romper la compatibilidad con versiones anteriores, POSIX definió un nuevo indicador en lugar de exigir un comportamiento específico para uno de los otros. Algunos sistemas como Linux tratan a los 3 de la misma manera, y también definen EAGAIN y EWOULDBLOCK con el mismo valor, pero los sistemas que desean mantener algún otro comportamiento heredado para la compatibilidad con versiones anteriores pueden hacerlo cuando se usan los mecanismos anteriores.

Los nuevos programas deben usar fcntl( ... O_NONBLOCK ... ) , estandarizado por POSIX.

En cada ejemplo y discusión que encuentro en el contexto de la programación de socket BSD, parece que la forma recomendada de establecer un descriptor de archivo en modo de E / S sin bloqueo es usar el indicador fcntl() para fcntl() , por ejemplo

int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK);

He estado haciendo programación de red en UNIX durante más de diez años, y siempre he usado la FIONBIO ioctl() para hacer esto:

int opt = 1; ioctl(fd, FIONBIO, &opt);

Nunca realmente pensé mucho sobre por qué. Lo aprendí de esa manera.

¿Alguien tiene algún comentario sobre los posibles méritos respectivos de uno u otro? Me imagino que el locus de portabilidad difiere un poco, pero no sé en qué medida ioctl_list(2) no habla de ese aspecto de los métodos ioctl individuales.


Como dijo @Sean, fcntl() está ampliamente estandarizado y, por lo tanto, está disponible en todas las plataformas. La función ioctl() es anterior a fcntl() en Unix, pero no está estandarizada en absoluto. Que el ioctl() funcionó para usted en todas las plataformas relevantes para usted es afortunado, pero no está garantizado. En particular, los nombres utilizados para el segundo argumento son arcanos y no son confiables en todas las plataformas. De hecho, a menudo son únicos para el controlador de dispositivo particular al que hace referencia el descriptor de archivo. (Las llamadas ioctl() utilizadas para un dispositivo gráfico mapeado en bit que se ejecuta en un Perq ICL que ejecuta PNX (Perq Unix) de hace veinte años nunca se tradujo a nada en ningún otro lado, por ejemplo).


Creo que fcntl() es una función POSIX. Donde como ioctl() es una cosa estándar de UNIX. Aquí hay una lista de POSIX io . ioctl() es algo muy específico del núcleo / controlador / sistema operativo, pero estoy seguro de que lo que utiliza funciona en la mayoría de los sabores de Unix. algunas otras cosas ioctl() solo pueden funcionar en ciertos sistemas operativos o incluso ciertas revoluciones de su kernel.