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);

私はUNIXで10年以上ネットワークプログラミングを行っており、FIONBIO ioctl()これを行うために常に呼び出しを使用しています。

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

その理由をあまり考えなかった。ちょうどそのようにそれを学びました。

誰かがどちらか一方の可能性のあるそれぞれの利点について解説をしていますか?移植性の軌跡は多少異なると思いますがioctl_list(2)、個々のioctlメソッドのその側面に触れていないので、どの程度かはわかりません。

回答:


134

標準化以前はioctl(... FIONBIO... )fcntl(... O_NDELAY...が)ありましたが、これらはシステム間で、また同じシステム内でも一貫性のない動作をしていました。たとえば、FIONBIOソケットやO_NDELAYttyで作業することはよくありましたが、パイプ、fifo、デバイスなどの多くの点で一貫性がありませんでした。また、ファイル記述子の種類がわからない場合は、両方を設定して確認する必要があります。しかし、それに加えて、利用可能なデータがない非ブロッキング読み取りも一貫性のない形で示されました。OSおよびファイル記述子のタイプに応じて、読み取りは0、またはerrno EAGAINの場合は-1、またはerrno EWOULDBLOCKの場合は-1を返します。今日でも、設定FIONBIOまたはO_NDELAYSolarisでは、データのない読み取りはttyまたはパイプでは0を返し、ソケットではerrno EAGAINで-1を返します。ただし、0はEOFでも返されるため、あいまいです。

POSIXはO_NONBLOCK、さまざまなシステムおよびファイル記述子タイプにわたって動作を標準化したの導入により、これに対処しました。既存のシステムは通常、下位互換性を損なう可能性のある動作の変更を避けたいため、POSIXは他の1つに特定の動作を強制するのではなく、新しいフラグを定義しました。Linuxのような一部のシステムは3つすべてを同じように扱い、EAGAINとEWOULDBLOCKを同じ値に定義しますが、下位互換性のために他のレガシー動作を維持したいシステムは、古いメカニズムが使用されている場合にそうすることができます。

新しいプログラムでは、POSIXで標準化されているfcntl(... O_NONBLOCK... を使用する必要があります)


6
このため、ioctl()を使用する傾向があります。これは、非ブロックモードを有効にするためのシステムコールがfcntl()に対して2つではなく1つだけになるためです。さらに、Windowsのioctlsocket()APIは、この機能の目的ではioctl()と同等です。
Wez Furlong、2012

nginxは、可能であればこれを実行し、「ioctl(FIONBIO)が単一のsyscallで非ブロッキングモードを設定する」というコメントを付けます。これで、接続を受け入れ、同じシステムコールで非ブロッキングモードにすることができるaccept2があります。
Eloff、2014年

6

@Seanが言ったように、fcntl()主に標準化されているため、プラットフォーム間で利用できます。このioctl()関数はfcntl()Unixでは古くなっていますが、標準化されていません。ioctl()あなたに関係のあるすべてのプラットフォームにわたってあなたのために働いたことは幸運ですが、保証されていません。特に、2番目の引数に使用される名前は難解で、プラットフォーム間で信頼できません。実際、多くの場合、これらはファイル記述子が参照する特定のデバイスドライバーに固有のものです。(ioctl()たとえば、20年前のPNX(Perq Unix)を実行しているICL Perqで実行されているビットマップグラフィックデバイスに使用された呼び出しは、他のどこにも変換されませんでした。)


6

fcntl()POSIX関数だと思います。どこioctl()が標準的なUNIXのものです。以下はPOSIX ioのリストです。 ioctl()非常にカーネル/ドライバー/ OS固有のものですが、使用するものがUnixのほとんどのフレーバーで動作すると確信しています。他のいくつかのioctl()ものは、特定のOSまたはカーネルの特定のリビジョンでのみ機能する場合があります。


AIX、Solaris、Linux、* BSD、およびIRIXでFIONBIOを問題なく使用しました。しかし、ええ、私はそれが例えばWindowsでは機能しないことを理解しています-それは非常に特定のカーネル実装への低レベルのインターフェースです。それでも、他に差別化要因はあるのでしょうか。
Alex Balashov
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.