7.1 ブロッキング
ブロッキング。聞いたことがあると思います---さて、一体何でしょう?一言で言えば、"ブロック" は技術用語で "スリープ" のことです。上で listener
を実行したとき、パケットが到着するまでただそこに座っていることに気付いたと思います。何が起こったかというと、recvfrom()
を呼び出したのですが、データがなかったので、recvfrom()
はデータが到着するまで "block"(つまり、そこで眠る)と言われているのです。
多くの関数がブロックします。accept()
がブロックします。すべての recv()
関数がブロックします。このようなことができるのは、ブロックすることが許されているからです。最初に socket()
でソケット記述子を作成するとき、カーネルはそれをブロッキングに設定します。もし、ソケットをブロッキングさせたくなければ、fcntl()
を呼び出す必要があります。
#include <unistd.h>
#include <fcntl.h>
.
.
.
sockfd = socket(PF_INET, SOCK_STREAM, 0);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
.
.
.
ソケットをノンブロッキングに設定することで、効果的にソケットの情報を "ポーリング" することができます。ノンブロッキングソケットから読み込もうとしたときに、そこにデータがない場合、ブロックすることは許されません---その際には -1
が返り、errno
には EAGAIN
または EWOULDBLOCK
がセットされます。
(待てよ--EAGAIN
や EWOULDBLOCK
を返すこともあるのか?どちらをチェックする?仕様では実際にあなたのシステムがどちらを返すかは指定されていないので、移植性のために両方チェックしましょう。)
しかし、一般的に言って、この種のポーリングは悪い考えです。ソケットのデータを探すためにプログラムをビジーウェイト状態にすると、流行遅れのように CPU 時間を吸い取られてしまうからです。読み込み待ちのデータがあるかどうかを確認するための、よりエレガントなソリューションが、次の poll()
の章で紹介されています。