0

我使用 Python 2.7 中的 asynchat 和邮箱模块编写了一个电子邮件服务器。在前台运行时,一切正常,并且在长时间的测试中保持稳定。但是,当作为守护进程分离时,对邮箱的访问会导致 asyncore.loop() 中出现错误文件描述符的异常。只有文件访问是一个问题。Socket 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 是如何添加到异步通道映射中的,或者为什么它在 close() 之后仍然存在。我不清楚哪个 fd 现在无效。也不清楚为什么在 shell 进程中运行时不会发生这种情况。

如果我使用线程,我可以看到这种情况,但我快速浏览了导入的模块,没有看到任何表明它们启动了单独的线程或进程的信息。此外,如果我继续以 root 身份运行而不是放弃给任何人,则行为不会改变。

肯定 asyncore 和邮箱模块在其他守护进程中使用。我觉得我一定遗漏了一些明显的东西。

4

1 回答 1

0

事实证明,电子邮件包正在关闭文件描述符 4,无论它是否拥有它。在我的例子中,fd 4 总是分配给日志文件。我通过打开一个分配为 fd 4 的文本文件进行验证,并将日志文件推送到 fd 5。在处理从邮箱读取的第一封电子邮件消息期间,该文本文件 fd 被关闭。

尝试调试电子邮件包占用了太多时间,所以我写了一个足以满足我需要的替代品,然后继续我的工作。

于 2016-05-15T16:31:49.470 回答