2012-04-25 109 views
2

我正在嘗試做一個簡單的Gmail客戶端。問題是我得到一個非常奇怪的迴應;其實我根本沒有得到SslStream.read的迴應。首先,當我以客戶端身份連接到Gmail服務器時,它的工作原理非常完美(Connect()方法),但是當我嘗試從電子郵件中獲取號碼時,再次使用SslStream.readleerMensaje()方法,它變得很奇怪,只是停止運行,網頁卡住加載。沒有得到SslStream.read的響應

這裏是我工作類:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Net; 
using System.Net.Sockets; 
using System.Net.Security; 
using System.Text; 
using System.Net.Mail; 

namespace GmailClient 
{ 
    public class GmailPop 
    { 
     private SslStream sslStream; 
     private String user; 
     private String pass; 

     public GmailPop(String user, String pass) 
     { 
      this.user = user; 
      this.pass = pass; 
     } 

     public bool Connect() 
     { 
      String response; 
      byte[] buffer = new byte[2048]; 
      int bytes = -1; 
      TcpClient server = new TcpClient("pop.gmail.com", 995); 
      sslStream = new SslStream(server.GetStream()); 
      sslStream.AuthenticateAsClient("pop.gmail.com"); 
      bytes = sslStream.Read(buffer, 0, buffer.Length); 
      response = Encoding.ASCII.GetString(buffer,0,bytes); 
      sslStream.Write(Encoding.ASCII.GetBytes("USER recent:" + user+"\r\n")); 
      bytes = sslStream.Read(buffer, 0, buffer.Length); 
      response = Encoding.ASCII.GetString(buffer,0,bytes); 
      if(response.StartsWith("+OK")){ 
       sslStream.Write(Encoding.ASCII.GetBytes("PASS "+pass+"\r\n")); 
       bytes = sslStream.Read(buffer,0,buffer.Length); 
       response = Encoding.ASCII.GetString(buffer, 0, bytes); 
       return response.StartsWith("+OK"); 
      } 
      return false; 
     } 
     public int numCorreos() 
     { 
      String res = escribirLeer("STAT"); 
      String[] resA = res.Split(' '); 
      int num = Int32.Parse(resA[1]); 
      return num; 
     } 
     public String leerMensaje() 
     { 
      int bytes = -1; 
      byte[] buffer = new byte[2048]; 
      String msg = ""; 
      do 
      { 
       bytes = sslStream.Read(buffer, 0, buffer.Length); 
       msg += Encoding.ASCII.GetString(buffer, 0, bytes); 
      } while (bytes != 0); 
      return msg; 
     } 
     public void escribirMsg(String msg) 
     { 
      byte[] buffer = Encoding.ASCII.GetBytes(msg); 
      sslStream.Write(buffer); 
      sslStream.Flush(); 
     } 
     public String escribirLeer(String msg) 
     { 
      escribirMsg(msg); 
      String respuesta = leerMensaje(); 
      return respuesta; 
     } 
    } 
} 

這裏是ASPX網頁調用該方法:

GmailPop client; 
     protected void Page_Load(object sender, EventArgs e) 
     { 
      if (Session["user"] != null && Session["pass"] != null) 
      { 
       String user = Session["user"].ToString(); 
       String pass = Session["pass"].ToString(); 

       client = new GmailPop(user, pass); 

       if (client.Connect()) 
       {      
        Session["active"] = true; 
        Response.Write(numCorreos()); 
       } 
       else 
       { 
        Session.Remove("pass"); 
        Response.Redirect("login.aspx?error=login"); 
       } 
      } 
      else 
      { 
       Response.Redirect("login.aspx"); 
      } 
     } 
    } 

回答

1

第一個問題是,你發送「STAT 「作爲命令,但所有命令都必須以」\ r \ n「結尾,所以您需要發送」STAT \ r \ n「。

這似乎是你也推斷從sslStream.Read(...)返回0代碼的消息結束,但是這種方法將不會返回0,直到流被關閉。在沒有更多數據等待讀取的情況下,Read()將會阻塞,等待更多數據到達,這就解釋了您所看到的掛起。

根據POP3 protocol specification,對於單行響應,您應該等待一個「\ r \ n」序列來指示響應的結束,以及對於那些導致多行響應的命令(例如,檢索消息數據),響應由一個「。」結束。在一行上(即行以「。\ r \ n」開始)。處理包含此終止序列的消息還有其他規則,所以我建議您自己閱讀協議規範。

+0

是的,我嘗試了你所說的,實際上我在read方法的文檔之前閱讀,並且它返回讀取的字節數,所以如果它在結束時應該返回0,問題是甚至在程序第一次達到該指令時調試程序,它只是在它運行該程序後立即停止調試。是一個很奇怪的行爲。 – 2012-04-25 11:55:32

+0

第一次調用Read()時掛起的原因是因爲命令必須以「\ r \ n」結尾。你只是發送「STAT」,但需要發送「STAT \ r \ n」。我將編輯我的答案以反映這一點。但是我的原始答案仍然存在 - 因爲當前代碼仍然期望Read()返回0(除非連接已關閉,否則它不會),所以即使您正確發送命令,它仍然會掛起,但是在第二次調用Read()。 – Iridium 2012-04-25 13:05:51

+0

謝謝你,我們有時候看不到的那些小聾人,因爲你們正在上課後的午夜。再次感謝 – 2012-04-25 19:16:21