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.