2009-07-19 9 views
78

すべての例と議論では、BSDソケットプログラミングのコンテキストで実行します。ファイル記述子を非ブロックI/Oモードに設定する推奨方法は、O_NONBLOCKフラグをfcntl()に設定します。私は10年以上にわたってUNIXネットワークプログラミングを行ってきたし、常にこれを行うにはFIONBIO ioctl()コールを使用していたUNIXノンブロッキングI/O:O_NONBLOCK対FIONBIO

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

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

は本当に理由に多くの思考を与えたことはありません。そのように学んだだけです。

いずれかの可能なそれぞれのメリットについて解説している人はいますか?私は可搬性の軌跡が幾分異なっていると考えていますが、ioctl_list(2)が個々のioctlメソッドのその側面を話していないことをどの程度知っていません。

答えて

114

前標準化へioctl(がありました。 .. FIONBIO ... )fcntl( ... O_NDELAY ... )しかし、これらはシステム間で一貫性がなく、同じシステム内でさえも動作しませんでした。例えば、FIONBIOはソケットで、O_NDELAYはttysで作業するのが一般的でした。パイプ、FIFO、デバイスなどの場合には矛盾が多くありました。あなたが持っていたファイルディスクリプタの種類がわからない場合は、両方を設定する必要があります。しかし、加えて、利用可能なデータを持たない非ブロッキング読み出しも一貫して示されていませんでした。 OSとファイル記述子のタイプに応じて、readは0を返すか、-1をerrno EAGAINに、-1をerrno EWOULDBLOCKに返します。今日でさえ、Solaris上でFIONBIOまたはO_NDELAYを設定すると、データがない状態でttyまたはパイプ上で0が返されます。ソケット上では-1がerrno EAGAINにな​​ります。ただし、0はEOFのために返されるのであいまいです。

POSIXは、異なるシステムとファイルディスクリプタタイプ間の動作を標準化したO_NONBLOCKの導入によりこれを解決しました。既存のシステムは通常、後方互換性を損なう可能性のある動作の変更を避けたいので、POSIXは他のものの特定の動作を強制するのではなく、新しいフラグを定義しました。 Linuxのようないくつかのシステムでは、3つすべて同じものを扱い、同じ値にEAGAINとEWOULDBLOCKを定義していますが、古い機構が使用されている場合、後方互換性のための他の従来の動作を維持したいシステムもあります。

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

+5

私はfcntl()に対して2つではなく非ブロッキングモードを有効にするために、1つのシステムコールしか必要としないので、ioctl()を使用する傾向があります。さらに、Windowsのioctlsocket()APIは、この機能のためにioctl()と同等です。 –

+0

nginxはできる場合はこれを行い、 "ioctl(FIONBIO)は単一のシステムコールで非ブロックモードを設定します"というコメントを付けます。今ではaccept2を使用して、接続を受け入れ、同じシステムコールの非ブロックモードにすることができます。 – Eloff

5

私は信じていますfcntl()はPOSIX関数です。ところで、ioctl()はUNIXの標準的なものです。ここにはPOSIX ioのリストがあります。 ioctl()は、非常にカーネル/ドライバ/ OS固有のものですが、私が使用しているものがUnixのほとんどのフレーバーで動作すると確信しています。いくつかの他のioctl()ものは特定のOSやカーネルの特定の回転だけでも動くかもしれません。

+0

私は問題なくAIX、Solaris、Linux、* BSD、IRIXでFIONBIOを使用しました。しかし、ええ、私はそれがWindows上ではうまくいかないことを理解しています。例えば、非常に特定のカーネル実装に対する低レベルのインタフェースです。それでも、他の差別化要因があるのだろうかと思います。 –

4

@Seanによると、fcntl()は主に標準化されており、プラットフォーム間で利用できます。 ioctl()関数は、Unixではfcntl()より前ですが、まったく標準化されていません。 ioctl()は、あなたと関連性のあるすべてのプラットフォームでうまく動作していますが、幸運ですが保証されていません。特に、第2引数に使用される名前は秘密であり、プラットフォーム間で信頼性がありません。実際には、ファイルディスクリプタが参照する特定のデバイスドライバに固有のことがよくあります。 (ビットマップグラフィックスデバイスは、20年前のPNX(PerqのUnix)を実行しているICL Perq上で実行するために使用ioctl()呼び出しは、たとえば、どこか他の何か他のものに変換することはありません。)

関連する問題