本文介绍了JavaMail:保持IMAPFolder.idle()活着的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个程序,需要监控Gmail帐户中的新邮件,为了尽快获取它们,我使用的是JavaMail的空闲功能。这是我用来调用folder.idle()的线程的代码片段:

I am making a program that needs to monitor a Gmail account for new messages, and in order to get them ASAP I am using JavaMail's idle feature. Here is a code snippet from the thread I am using to call folder.idle():

//Run method that waits for idle input. If an exception occurs, end the thread's life.
public void run() {

    IMAPFolder folder = null;

            try {
                folder = getFolder();
                while(true)
                {
                  //If connection has been lost, attempt to restore it
                  if (!folder.isOpen())
                      folder = getFolder();
                  //Wait until something happens in inbox
                  folder.idle(true);
                  //Notify controller of event
                  cont.inboxEventOccured();
                }
            }
            catch (Exception ex) {
                ex.printStackTrace();
            }
             System.out.println("MailIdleWaiter thread ending.");
}

getFolder()方法基本上打开与IMAP服务器的连接并打开收件箱。

The getFolder() method basically opens the connection to the IMAP server and opens the inbox.

这种情况有效,但在10分钟左右后它就会停止更新(不会抛出任何异常)。

This works for a while, but after 10 minutes or so it stops getting updates (no exception is thrown).

我正在寻找保持连接活着的建议。我是否需要第二个线程,其唯一的作用是睡眠并每10分钟更新一次idle()线程,或者是否有更简单/更好的方法?

I am looking for suggestions to keep the connection alive. Do I need a second thread whose only role is to sleep and renew the idle() thread every 10 minutes or is there an easier/better way?

提前致谢。

推荐答案

一个常见的错误是假设IDLE命令会无限期地发布更新。但是,定义IDLE扩展名的表明:

A common mistake is to assume an IDLE command will keep posting updates indefinitely. However, the RFC 2177, that defines the IDLE extension states:

如果客户端运行了IDLE命令
,服务器可以认为客户端处于非活动状态,如果这样的服务器有一个非活动超时,它可能会在客户端关闭客户端时记录
超时期限结束。因为
,建议使用IDLE的客户端终止IDLE,并且至少每29分钟重新发出
以避免被注销。
这仍然允许客户端接收即时邮箱更新,即使是
,但它只需要半小时间隔轮询。

尤其是GMail,具有更低的超时,如你所说,大约10分钟。

GMail in particular, has a much lower timeout, as you say, around 10 minutes.

我们只需每9分钟左右重新发出一次IDLE命令它的工作原理。 javax.mail API无法为IDLE命令设置超时,因此您需要第二个线程来移动它。

We simply need to reissue the IDLE command every 9 minutes or so for it to work. The javax.mail APIs have no way to set a timeout for the IDLE command, so you will need a second thread to move around this.

第一种方法是让第二个线程中断第一个线程,处理异常并忽略它。然而,这将允许没有干净的方式来关闭线程,所以我不会推荐它。更简洁的方法是让第二个线程向服务器发出NOOP命令。它什么都不做,但足以让IDLE中止并重新发布。

A first approach would be to have the second thread interrupt the first one, handling the exception and ignoring it. This however, would allow for no clean way to shutdown the thread, so I won't recomend it. A much cleaner way is to have the second thread issue a NOOP command to the server. This does nothing at all, but is enough to have IDLE abort and be reissued.

我这里提供了一些代码来执行此操作:

I here provide some code to do this:

public void startListening(IMAPFolder imapFolder) {
    // We need to create a new thread to keep alive the connection
    Thread t = new Thread(
        new KeepAliveRunnable(imapFolder), "IdleConnectionKeepAlive"
    );

    t.start();

    while (!Thread.interrupted()) {
        LOGGER.debug("Starting IDLE");
        try {
            imapFolder.idle();
        } catch (MessagingException e) {
            LOGGER.warn("Messaging exception during IDLE", e);
            throw new RuntimeException(e);
        }
    }

    // Shutdown keep alive thread
    if (t.isAlive()) {
        t.interrupt();
    }
}

/**
 * Runnable used to keep alive the connection to the IMAP server
 *
 * @author Juan Martín Sotuyo Dodero <[email protected]>
 */
private static class KeepAliveRunnable implements Runnable {

    private static final long KEEP_ALIVE_FREQ = 300000; // 5 minutes

    private IMAPFolder folder;

    public KeepAliveRunnable(IMAPFolder folder) {
        this.folder = folder;
    }

    @Override
    public void run() {
        while (!Thread.interrupted()) {
            try {
                Thread.sleep(KEEP_ALIVE_FREQ);

                // Perform a NOOP just to keep alive the connection
                LOGGER.debug("Performing a NOOP to keep alvie the connection");
                folder.doCommand(new IMAPFolder.ProtocolCommand() {
                    public Object doCommand(IMAPProtocol p)
                            throws ProtocolException {
                        p.simpleCommand("NOOP", null);
                        return null;
                    }
                });
            } catch (InterruptedException e) {
                // Ignore, just aborting the thread...
            } catch (MessagingException e) {
                // Shouldn't really happen...
                LOGGER.warn("Unexpected exception while keeping alive the IDLE connection", e);
            }
        }
    }
}

这篇关于JavaMail:保持IMAPFolder.idle()活着的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 11:02