acceptエラーの原因がpipe
正月浮かれのなか、自宅サーバで動かしているサーバプロセスにエラーが大量発生して驚きました。
自宅サーバの環境はMacOSⅩでソースはCで組んだものでした。
エラーログ
[ERROR]Bad file descriptor
[ERROR]***************************************************
[ERROR]7時44分55秒
[ERROR]accept() にてエラー [pID:10126]
[ERROR]Bad file descriptor
[ERROR]***************************************************
[ERROR]7時44分55秒
[ERROR]accept() にてエラー [pID:10126]
[ERROR]Bad file descriptor
[ERROR]***************************************************
[ERROR]7時44分55秒
[ERROR]accept() にてエラー [pID:10126]
[ERROR]Bad file descriptor
[ERROR]***************************************************
acceptは、ソケット通信において、クライアントからアクセスがあったら、そのクライアントと1対1の通信ができるfile descriptorを生成してくれる関数です。[詳細説明]
ディスクリプタの上限数に達した?
エラーに出てきたようにaccpt関数ででも、ファイル・ディスクリプタを取得できます。クライアントマシンとの入出力に使うファイル・ディスクリプタです。
初めは1プロセスで使用可能なファイル・ディスクリプタの上限に引っかかったのかな?と思いました。
$ ulimit -n
256
これで1つのプロセスで利用可能なディスクリプタ数を確認できます。MacOSⅩでは256個がデフォルトで、ソケット通信時にはこれが支障になります。
accept関数により1クライアント1ファイル・ディスクリプタに関連付けされますが、上限があるのでクライアントが256人以上アクセスしてきた場合、acceptはエラーを返してしまうのです。
しかしログを見る限り、256ものクライアントは接続してきていません。
(そして上限も拡張済みだった)
原因はpipe
プログラムでは共有パイプを利用していました。
これがバグをはらんでいました。
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/pipe.2.html
によると、
プロセス間通信に使用できる単方向のデータチャネルである。
「単方向」であることが義務づけられているということを知りませんでした。
入力側でデータを取り出した後、取り出したことをpipeに書き込んでしまっていました。入力側で書きこみしてしまうと単方向になりません。(入力側は入力しかできない、当然)
考えれば当然、UNIXコマンドでもデータが逆戻りすることなんてありません。
そして、おそらくは逆戻りしてしまったデータがファイル・ディスクリプタの管理領域を破壊していたのだと思います。
その状態で、パイプをcloseしたら、直後からacceptにエラーが発生しています。
パイプを単方向にちゃんとしたら、このエラーは発生しなくなりました。