我使用Python 2.7中的asynchat和邮箱模块编写了一个电子邮件服务器。在forground中运行时,一切正常,并且在长时间的测试中保持稳定。但是,当作为守护程序分离时,访问邮箱会在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)
以下部分涉及加载parser.py和feedparser.py模块,这些模块本身使用mmap2打开和关闭多个文件描述符。
因此,电子邮件文件的fd已关闭但不久之后,fd显示在选择列表中。我不清楚如何将fd添加到asyncore通道映射中,或者为什么它在close()之后仍然存在。我不清楚哪个fd现在无效。也不清楚为什么在shell进程中运行时不会发生这种情况。
如果我使用线程,我可以看到这种情况发生,但我已经快速浏览了导入的模块,并没有看到任何迹象表明它们启动了单独的线程或进程。此外,如果我继续以root身份运行而不是删除到nobody,则行为不会改变。
当然,asyncore和mailbox模块在其他守护进程中使用。我觉得我必须遗漏一些明显的东西。
答案 0 :(得分:0)
事实证明,电子邮件包正在关闭文件描述符4,无论它是否拥有它。在我的实例中,fd 4始终分配给日志文件。我通过打开分配了fd 4的文本文件进行验证,并将日志文件推送到fd 5.文本文件fd在处理从邮箱读取的第一封电子邮件时被关闭。
尝试调试电子邮件包占用了太多时间,所以我写了一个足以满足我需求的替代品并继续我的工作。