2017-04-11 35 views
0

我想实现一个简单的IMAP客户端。我可以连接到服务器,收到它的问候语,但似乎在login命令后收到响应时出现问题。Java中的IMAP客户端(仅限套接字)在接收时挂起

我知道IMAP行以\r\n.\r\n结尾,但似乎一次只读一个字节根本不起作用,我不知道为什么。

我的代码:

class NewClass { 

    public static String readAll(Socket socket, String end) throws IOException { 
     BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
     StringBuilder sb = new StringBuilder(); 
     String line; 

     while (!sb.toString().endsWith(end)) 
     { 
      char c = (char)reader.read(); 
      sb.append(c); 
     } 
     return sb.toString(); 
    } 

    public static void main(String[] args) throws IOException { 
     String host = "x.x.x.x"; 
     int port = 143; 

     Socket socket = new Socket(host, port); 

     BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
     PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); 

     // server's greeting 
     String initreply = readAll(socket, "\r\n"); 
     System.out.println(initreply); 

     // log me in 
     String login_cmd = "A1 LOGIN user pass\r\n"; 
     writer.print(login_cmd); 
     writer.flush(); 
     String loginreply = readAll(socket, "\r\n"); 
     System.out.println(loginreply); 

    } 
} 
+0

Oy,您每次阅读时都会创建新的BufferedReaders。每个缓冲读取器可能会预读,然后将其扔掉。 – Max

回答

1

没有什么简单关于IMAP,这是一个非常复杂的协议从头开始实施。请考虑查找预先存在的IMAP库。这就是说,很明显,你没有阅读IMAP规范RFC 3501(特别是section 2.2 "Commands and Responses"),或者你会知道你的代码失败的原因。您的代码不符合规范。

特别是:

  1. 你不发送你的LOGIN命令的末尾尾随\r\n,所以服务器将不会发送任何回应。 PrintWriter.print()不打印换行符。 PrintWriter.println()确实,但它只打印LF,但IMAP使用CRLF。因此,您需要在发送到服务器的每个命令末尾包含\r\n

  2. 您没有正确读取服务器响应。您必须读取行,将*+标记纳入考虑范围,直到您收到一行开始与您用于标记LOGIN命令的标记相同的A1标记。如果使用BufferedReader.readLine()而不是单独将字符读入StringBuilder,则逻辑将更容易实现。从技术上讲,你应该在后台线程中异步执行读取操作,因为IMAP是异步协议。一次可以有多个命令在飞行,并且在命令响应之间可能有服务器发送的未经请求的数据。响应中的标签会告诉您哪些命令正在响应,如果有的话。无论哪个命令生成它们,以前缀标记的未加标签的响应都应按原样处理。

1

您可以随时知道你的程序采取线程转储和检查目标线程(提示的堆栈跟踪挂起:如果需要,可以Thread.interrupt()在插座的作业等待读)。

无论如何,您的程序会因为等待服务器的更多输入而阻塞,并且服务器无法发送任何内容。始终设置超时开始阅读之前:

Socket socket = new Socket(); 
socket.connect(new InetSocketAddress(host, port), 1000); 
socket.setSoTimeout(1000); 
readAll(); 

此时你的程序可能会抛出一个SocketTimeoutException,你会看到一个电话BufferedReader.read()最顶层的框架之中。假设IMAP邮件正是一条线长,通过CRLF终止,读出程序可能是:

Scanner scanner = new Scanner(/* initialize from socket */); 
scanner.useDelimiter("\r\n"); 
String response = scanner.nextLine(); 

提示:安装嗅探器像Wireshark来更好地了解发生了什么事情。

相关问题