无法从 IMAP 服务器注销 (Ruby)

Cannot logout from IMAP server (Ruby)

使用 Ruby 我正在编写一个守护程序,用于同步来自 IMAP 服务器的邮件。我有多个帐户,我一个接一个地登录并下载未读消息。但是我无法重复使用现有的 IMAP 服务器连接。

这是我想要做的粗略示例:

require 'net/imap'

imap = Net::IMAP.new('imap.example.com')

imap.login('login@example.com', 'R2D2C3PO')
imap.select('INBOX')

# interacting with the server, like fetching the messages etc.
# for example:
puts imap.fetch(3, "BODYSTRUCTURE")

# now I want to log out of the account and log in with another
imap.logout

imap.login('anotherlogin@example.com', 'R2D2C3PO')
imap.select('INBOX')    

# again - interacting with the server
puts imap.fetch(3, "BODYSTRUCTURE")

imap.disconnect

然而调用logout方法时出现异常:

/usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/monitor.rb:110:in `sleep': No live threads left. Deadlock? (fatal)
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/monitor.rb:110:in `wait'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/monitor.rb:110:in `wait'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/net/imap.rb:1166:in `get_tagged_response'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/net/imap.rb:1225:in `block in send_command'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/net/imap.rb:1207:in `send_command'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/net/imap.rb:435:in `login'
        from test.rb:13:in `<main>'

我完全被线程异常搞糊涂了,因为守护进程只是单线程的。在引擎盖下,进程在等待服务器响应时挂在条件变量上。为什么调用之前的方法(LOGINSELECT等命令)没有问题,发送LOGOUT命令时却出现问题?


编辑:

我不知何故完全错过了一个事实,即 LOGOUT 命令使与 IMAP 服务器的连接不再可用(正如@HolgerJust 指出的那样)。虽然我重用连接的想法惨遭失败,但要点仍然成立:发送LOGOUT命令时抛出异常,此时仍然是一个合法的动作,不应该造成任何麻烦。

从 IMAP 会话注销后,您必须创建一个新连接才能执行任何进一步的命令。注销后,不允许进一步重新使用连接。

引用自RFC 3501

The LOGOUT command informs the server that the client is done with the connection. The server MUST send a BYE untagged response before the (tagged) OK response, and then close the network connection.

在 Ruby 代码中,这实际上意味着在您对 imap 对象调用 logout 之后,您不能再用它做任何有用的事情。相反,通过创建新的 imap 对象来创建新连接。