一个常见的错误是假设IDLE命令将不间断地发布更新.然而,定义IDLE扩展的
RFC 2177表示:
The server MAY consider a client inactive if it has an IDLE command
running, and if such a server has an inactivity timeout it MAY log
the client off implicitly at the end of its timeout period. Because
of that, clients using IDLE are advised to terminate the IDLE and
re-issue it at least every 29 minutes to avoid being logged off.
This still allows a client to receive immediate mailbox updates even
though it need only “poll” at half hour intervals.
特别是GMail,如你所说,大约10分钟,有一个低得多的超时时间.
我们只需要每9分钟左右重新发行一次IDLE命令,让它工作. javax.mail API无法为IDLE命令设置超时,因此您将需要一个第二个线程来移动此操作.
第一种方法是让第二个线程中断第一个线程,处理异常并忽略它.然而,这将允许没有干净的方式来关闭线程,所以我不会推荐它.一个更清洁的方法是让第二个线程向服务器发出一个NOOP命令.这完全没有,但是足够让IDLE中止并重新发行.
我在这里提供一些代码来做到这一点:
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
*/
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);
}
}
}
}