UNIX 비 블로킹 I / O : O_NONBLOCK 대 FIONBIO


92

나는 BSD 소켓 프로그래밍의 맥락에서 걸쳐 실행할 때마다 예와 토론에서는 I를 블로킹에 파일 기술자를 설정하기 위해 권장되는 방법은 / O 모드가 사용하고있는 것 같습니다 O_NONBLOCK플래그를 위해 fcntl()예를 들면,

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

저는 10 년 넘게 UNIX에서 네트워크 프로그래밍을 해왔고 항상이 FIONBIO ioctl()호출을 사용 했습니다.

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

그 이유에 대해 정말 많이 생각하지 않았습니다. 그렇게 배웠습니다.

누구든지 둘 중 하나의 가능한 장점에 대한 논평이 있습니까? 나는 이식성 궤적이 다소 다를 것이라고 생각하지만 ioctl_list(2)개별 ioctl방법의 측면에 대해 말하지 않는 정도를 알지 못합니다 .

답변:


135

표준화 이전에는 ioctl(... FIONBIO... )fcntl(... O_NDELAY... )이 있었지만 이는 시스템간에, 심지어 동일한 시스템 내에서도 일관성없이 작동했습니다. 예를 들어, FIONBIO소켓 O_NDELAY에서 작업하고 tty에서 작업 하는 것이 일반적이었으며 파이프, fifo 및 장치와 같은 것에 대한 많은 불일치가있었습니다. 그리고 어떤 종류의 파일 디스크립터를 가지고 있는지 모른다면 두 가지를 모두 설정해야합니다. 그러나 또한 사용 가능한 데이터가없는 비 차단 읽기도 일관성없이 표시되었습니다. OS 및 파일 설명 자의 유형에 따라 읽기는 0, errno EAGAIN의 경우 -1, errno EWOULDBLOCK의 경우 -1을 반환 할 수 있습니다. 오늘도 설정 FIONBIO이나O_NDELAYSolaris에서는 데이터가없는 읽기가 tty 또는 파이프에서 0을 반환하거나 소켓에서 errno EAGAIN과 함께 -1을 반환합니다. 그러나 0은 EOF에 대해서도 반환되므로 모호합니다.

POSIX O_NONBLOCK는 다양한 시스템 및 파일 설명자 유형에서 동작을 표준화 한을 도입하여이 문제를 해결했습니다 . 기존 시스템은 일반적으로 이전 버전과의 호환성을 깨뜨릴 수있는 동작 변경을 피하려고하기 때문에 POSIX는 다른 시스템 중 하나에 대해 특정 동작을 지정하는 대신 새 플래그를 정의했습니다. Linux와 같은 일부 시스템은 3 개를 모두 동일하게 취급하고 EAGAIN 및 EWOULDBLOCK도 동일한 값으로 정의하지만 이전 버전과의 호환성을 위해 다른 레거시 동작을 유지하려는 시스템은 이전 메커니즘을 사용할 때 그렇게 할 수 있습니다.

새 프로그램은 POSIX에 의해 표준화 된대로 fcntl(... O_NONBLOCK...를 사용해야합니다 ).


6
나는 이것을 위해 ioctl ()을 사용하는 경향이 있는데, fcntl ()에 대해 두 개가 아닌 비 차단 모드를 활성화하는 데 하나의 시스템 호출 만 필요하기 때문입니다. 또한 Windows ioctlsocket () API는이 기능을 위해 ioctl ()과 동일합니다.
Wez Furlong 2012 년

nginx는 가능한 경우이를 수행하고 "ioctl (FIONBIO)는 단일 시스템 호출로 비 차단 모드를 설정합니다."라는 주석으로 표시합니다. 이제 연결을 수락하고 동일한 시스템 호출에서 비 차단 모드로 전환 할 수있는 accept2가 있습니다.
Eloff

6

@Sean이 말했듯 fcntl()이 거의 표준화되어 있으므로 여러 플랫폼에서 사용할 수 있습니다. 이 ioctl()함수 fcntl()는 Unix에서 이전보다 오래 되었지만 전혀 표준화되지 않았습니다. (가) 그건 ioctl()당신에게 모든 걸쳐 당신을 위해 관련의 플랫폼을했다 다행이지만, 보장 할 수 없습니다. 특히 두 번째 인수에 사용 된 이름은 난해하고 플랫폼간에 신뢰할 수 없습니다. 실제로 파일 설명자가 참조하는 특정 장치 드라이버에 고유 한 경우가 많습니다. ( ioctl()예를 들어, 20 년 전 PNX (Perq Unix)를 실행하는 ICL Perq에서 실행되는 비트 맵 그래픽 장치에 사용 된 호출은 다른 곳으로 번역되지 않았습니다.)


6

나는 fcntl()POSIX 기능 이라고 생각 합니다. ioctl()표준 UNIX는 어디에 있습니까 ? 다음은 POSIX io 목록입니다 . ioctl()매우 커널 / 드라이버 / OS에 특화된 것이지만 사용하는 것이 대부분의 유닉스 버전에서 작동한다고 확신합니다. 다른 ioctl()것들은 특정 OS 또는 커널의 특정 rev에서만 작동 할 수 있습니다.


저는 AIX, Solaris, Linux, * BSD 및 IRIX에서 FIONBIO를 문제없이 사용했습니다. 그러나 예, 예를 들어 Windows에서는 작동하지 않을 것임을 이해합니다. 이는 매우 특정한 커널 구현에 대한 저수준 인터페이스입니다. 그래도 다른 차별화 요소가 있는지 궁금합니다.
Alex Balashov
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.