2017-04-11 36 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來更好地瞭解發生了什麼事情。

相關問題