Python 2.7 の asynchat モジュールとメールボックス モジュールを使用して電子メール サーバーを作成しました。フォアグラウンドで実行すると、すべて正常に動作し、長期間のテストでも安定しています。ただし、デーモンとしてデタッチされている場合、メールボックスへのアクセスにより、asyncore.loop() で不正なファイル記述子の例外が発生します。ファイルアクセスのみが問題です。ソケット I/O は引き続き問題なく動作します。
__init__()
ファイルがfound_terminator() 関数で開かれるか後で開かれるかは問題ではないようです。
Schroeder の ActiveState レシピ 278731 のコードを使用してプロセスを切り離していますが、別のデーモン モジュールを使用しても症状は変わりません。
フローを示すための擬似コードを次に示します。
createDaemon()
s = myServer() # subclass of asynchat.async_chat
dropPermissions #setuid nobody
asyncore.loop()
物事が爆発したときのstrace出力は次のとおりです。
open("/tmp/MailboxDir/cur/1462562219.M374224P24795Q1.i7", O_RDONLY|O_LARGEFILE) = 8
fstat64(8, {st_mode=S_IFREG|0644, st_size=36, ...}) = 0
...
...
read(8, "To: you\nFrom: me\nSubject: test\n\n"..., 8192) = 36
read(8, "", 4096) = 0
read(8, "", 8192) = 0
close(8) = 0
...
stat64("/tmp/MailboxDir/cur/1462562219.M374224P24795Q1.i7", {st_mode=S_IFREG|0644, st_size=36, ...}) = 0
send(7, "+OK POP3 server ready\r\n", 23, 0) = 23
select(8, [4 5 6 7], [], [4 5 6 7], {30, 0}) = -1 EBADF (Bad file descriptor)
省略された部分には、mmap2 を使用していくつかのファイル記述子を開いたり閉じたりする parser.py および feedparser.py モジュールのロードが含まれます。
したがって、電子メール ファイルの fd は閉じられますが、その直後にその fd が選択リストに表示されます。fd が asyncore チャネル マップにどのように追加されるのか、または close() の後にまだ存在する理由は明確ではありません。fd のどれが現在無効であるかは明確ではありません。また、シェル プロセスで実行しているときにこれが発生しない理由も明らかではありません。
スレッドを使用していた場合、これが発生していることを確認できますが、インポートされたモジュールをざっと調べたところ、別のスレッドまたはプロセスを起動していることを示すものは何も表示されません。また、nobody にドロップするのではなく、root として実行し続けても、動作は変わりません。
確かに、asyncore およびメールボックス モジュールは他のデーモンで使用されています。明らかな何かが欠けているに違いないと感じています。