2014-09-10 132 views
0

我正在創建一個項目,它將讀取郵件列表並使用外部庫,將查找該域的MX記錄,並使用telnet來確定是否或者不存在該電子郵件。如何以線程安全方式添加延遲(TcpClient)

到目前爲止,我已經設法使它稍微工作 - 但是由於代碼運行的速度有多快,我相信我正嘗試讀取服務器的響應,比發送更快。 (我認爲這是因爲代碼在沒有調試的情況下運行時會返回空字符串,斷點返回一切正常。)

爲了反作用,我在代碼周圍添加了Thread.Sleep(),所以我可以等待對於響應,這可以工作,但會鎖定線程並停止響應幾分鐘。

如何在不鎖定UI的情況下執行此任務?
這裏是從哪裏的問題是類的代碼 -

class TelnetConnection 
{ 
    TcpClient tcpClient; 
    List<char> reply; 
    public TelnetConnection(string hostname, int port) 
    { 
     tcpClient = new TcpClient(); 
     tcpClient.BeginConnect(hostname, port, null, null); 
     Thread.Sleep(2000); 
    } 

    public List<char> GetReply() 
    { 
     reply = new List<char>(); 
     StringBuilder sb = new StringBuilder(); 
     while (tcpClient.Available > 0) 
     { 
      ParseTelnet(sb); 
     } 
     for (int i = 0; i < sb.Length; i++) 
     { 
      reply.Add(sb[i]); 
     } 
     return reply; 
    } 
    public List<char> Greet(string greeting) 
    { 
     WriteLine(greeting); 
     Thread.Sleep(2000); 
     return GetReply(); 
    } 
    public List<char> MailFrom(string mailFrom) 
    { 
     WriteLine(string.Concat("MAIL FROM: <", mailFrom, ">")); 
     Thread.Sleep(2000); 
     return GetReply(); 
    } 
    public List<char> RcptTo(string rcptTo) 
    { 
     WriteLine(string.Concat("RCPT TO: <", rcptTo, ">")); 
     Thread.Sleep(2000); 
     return GetReply(); 
    } 

    public void WriteLine(string cmd) 
    { 
     Write(cmd + "\n"); 
    } 

    public void Write(string cmd) 
    { 
     if (!tcpClient.Connected) return; 
     byte[] buf = System.Text.ASCIIEncoding.ASCII.GetBytes(cmd.Replace("\0xFF", "\0xFF\0xFF")); 
     tcpClient.GetStream().Write(buf, 0, buf.Length); 
    } 

    public bool IsConnected 
    { 
     get { return tcpClient.Connected; } 
    } 

    // Method from external library 
    void ParseTelnet(StringBuilder sb) 
    { 
      try 
      { 
       int input = tcpClient.GetStream().ReadByte(); 
       switch (input) 
       { 
        case -1: 
         break; 
        case (int)Verbs.IAC: 
         // interpret as command 
         int inputverb = tcpClient.GetStream().ReadByte(); 
         if (inputverb == -1) break; 
         switch (inputverb) 
         { 
          case (int)Verbs.IAC: 
           //literal IAC = 255 escaped, so append char 255 to string 
           sb.Append(inputverb); 
           break; 
          case (int)Verbs.DO: 
          case (int)Verbs.DONT: 
          case (int)Verbs.WILL: 
          case (int)Verbs.WONT: 
           // reply to all commands with "WONT", unless it is SGA (suppres go ahead) 
           int inputoption = tcpClient.GetStream().ReadByte(); 
           if (inputoption == -1) break; 
           tcpClient.GetStream().WriteByte((byte)Verbs.IAC); 
           if (inputoption == (int)Options.SGA) 
            tcpClient.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WILL : (byte)Verbs.DO); 
           else 
            tcpClient.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WONT : (byte)Verbs.DONT); 
           tcpClient.GetStream().WriteByte((byte)inputoption); 
           break; 
          default: 
           break; 
         } 
         break; 
        default: 
         sb.Append((char)input); 
         break; 
       } 
      } 
      catch (Exception ex) 
      { 
       throw new Exception(ex.Message, ex); 
      } 
    } 
} 
+0

您可能想使用[library](http://sourceforge.net/projects/dotnettelnet/)來簡化操作。 – CSharpie 2014-09-10 19:52:28

回答

2

刪除所有睡覺。你根本無法知道服務器響應需要多長時間。

取而代之的是,同意從服務器發送到客戶端的數據中的標記,並標記響應的結束。

在GetReplay中從流中讀取,直到遇到標記並返回。

編輯它看起來像ParseTelnet方法試圖做這樣的事情。確保服務器正在發送您期望的內容。

另一種方法是讓服務器首先發送回復的長度,這樣客戶端所要做的就是讀取該字節數量。

像這樣的協議被稱爲協議。

爲防止阻塞UI,請使用NetworkStream的* Async方法異步執行發送和讀取操作。

+1

除了「協議」另一個術語尋找谷歌搜索是[「消息框」](http://blog.stephencleary.com/2009/04/message-framing.html) – 2014-09-10 19:51:19

+0

@ScottChamberlain - 有趣的文章,很高興看到我的想法反映:)謝謝。 – 2014-09-10 19:52:36

+0

@ RayB151 - 你有沒有發現這個問題?什麼問題? – 2014-09-12 08:37:37