2015-08-15 67 views
0

如果這是一個補救問題,我很抱歉。首先,C#是我學習的第一門編程語言,我已經在過去的一個月裏向自己介紹了基礎知識+。在我的應用程序中,我使用簡約的telnet庫來進行telnet連接並執行命令。問題是我有大約2000個不同的客戶端可以連接,並且大多數是連接到單元。當我用提示快速地向他們telnet一些響應時,在極少數情況下,他們可能需要長達9秒纔會提供登錄提示。簡約telnet提示等待時間

我想要做的就是修改簡約的telnet代碼,等待登錄提示部分長達9秒。

我已經試過到目前爲止正在改變預定義的超時爲9000:

class Telnet 
{ 
    TcpClient tcpSocket; 
    // default timeout 9000 
    int TimeOutMs = 9000; 

我:

string s = tc.Login("root", "pass", 9000); 

改變了超時的telnet類的內部,9000和其間的每一組合取代了原來的代碼:

if (prompt != "#" && prompt != "$" && prompt != ":") 
throw new Exception("Connection failed"); 

與我自己的代碼:

while (prompt != "#" && prompt != "$" && prompt != ":" && delay != 19) 
{ 
delay ++ 
System.Threading.Thread.Sleep(500); 
if (delay = 12) 
{ 
updateHistoryWindow(this, "Unit is taking a long time to respond"); 
} 
if (delay = 19) 
{ 
throw new Exception("Connection failed"); 
updateHistoryWindow(this, "Unit did not display a login prompt"); 
} 
} 

使用While命令代替原來的if命令似乎根本不起作用。它不會等待while循環,它的行爲就像它首先超時一樣。

我的應用程序目前分別設置爲2500/2500超時,所有典型的連接都很好。如果我將這些超時值更改爲9000,那麼與典型的18秒相比,連接需要一分鐘或更長時間。我希望儘可能快地保持連接速度,只需等待登錄提示所需的時間,並且在發送命令到服務器之間沒有9秒的延遲。從理論上講,需要5秒鐘的時間才能完成操作的系統需要23秒才能完成操作(其他響應不會像登錄響應那樣延遲)。

  • 首先關閉哪個超時會做什麼?是我的Form1中的連接本身和telnet.cs文件中發送命令之間的延遲?
  • 我該如何適當延遲登錄提示,但仍然保持過程的其餘部分快速運行。目前,當我更改超時變量時,它會使每個連接永遠持續下去。
  • 我可以不使用指定的超時並使用我自己的while循環,我甚至需要這樣做嗎?
  • 什麼是Telnet.cs文件與 「oldTimeOutMs」, 「TimeOutMs」 和 「LoginTimeOutMs」 做

下面是我對初始化連接代碼:

try 
    { 
    int delay = 0; 
    Telnet tc = new Telnet(MyGlobals.IP, 23); 
    //login with user, password, using a timeout of 2500ms, and show server output 
    string s = tc.Login("root", "pass", 2500); 
    Console.Write(s); 
    // Check server output to see if it responds 
    string prompt = s.TrimEnd(); 
    prompt = s.Substring(prompt.Length - 1, 1); 
    while (prompt != "#" && prompt != "$" && prompt != ":" && delay != 19) 
    { 
    delay ++ 
    System.Threading.Thread.Sleep(500); 
    if (delay = 12) 
    { 
    updateHistoryWindow(this, "Unit is taking a long time to respond"); 
    } 
    if (delay = 19) 
    { 
    throw new Exception("Connection failed"); 
    updateHistoryWindow(this, "Unit did not display a login prompt"); 
    } 
    } 
    prompt = ""; 
    // while connected 
    if (tc.IsConnected) 
    { etc.... 

這裏是大頭來自簡約telnet的telnet.cs供參考:

namespace MYApp 
    { 
     enum Verbs 
     { 
      WILL = 251, 
      WONT = 252, 
      DO = 253, 
      DONT = 254, 
      IAC = 255 
     } 

     enum Options 
     { 
      SGA = 3 
     } 

     class Telnet 
     { 
      TcpClient tcpSocket; 
      // default timeout was 2500 
      int TimeOutMs = 2500; 

      public Telnet(string Hostname, int Port) 
      { 
       tcpSocket = new TcpClient(Hostname, Port); 
      } 

      public string Login(string Username, string Password, int LoginTimeOutMs) 
      { 
       int oldTimeOutMs = TimeOutMs; 
       TimeOutMs = LoginTimeOutMs; 
       string s = Read(); 
       if (s.TrimEnd().EndsWith(" ")) 
        throw new Exception("Failed to connect : no login prompt"); 
       WriteLine(Username); 
       s += Read(); 
       if (!s.TrimEnd().EndsWith(":")) 
        throw new Exception("Failed to connect : no password prompt"); 
       WriteLine(Password); 
       s += Read(); 
       TimeOutMs = oldTimeOutMs; 
       return s; 
      } 
      public void WriteLine(string cmd) 
      { 
       Write(cmd + "\n"); 
      } 
      public void Write(string cmd) 
      { 
       if (!tcpSocket.Connected) return; 
       byte[] buf =  System.Text.ASCIIEncoding.ASCII.GetBytes(cmd.Replace("\0xFF", "\0xFF\0xFF")); 
     tcpSocket.GetStream().Write(buf, 0, buf.Length); 
    } 

    public string Read() 
    { 
     if (!tcpSocket.Connected) return null; 
     StringBuilder sb = new StringBuilder(); 
     do 
     { 
      ParseTelnet(sb); 
      System.Threading.Thread.Sleep(TimeOutMs); 
     } while (tcpSocket.Available > 0); 
     return sb.ToString(); 
    } 

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

    void ParseTelnet(StringBuilder sb) 
    { 
     while (tcpSocket.Available > 0) 
     { 
      int input = tcpSocket.GetStream().ReadByte(); 
      switch (input) 
      { 
       case -1: 
        break; 
       case (int)Verbs.IAC: 
        // interpret as command 
        int inputverb = tcpSocket.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 = tcpSocket.GetStream().ReadByte(); 
          if (inputoption == -1) break; 
          tcpSocket.GetStream().WriteByte((byte)Verbs.IAC); 
          if (inputoption == (int)Options.SGA) 
           tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WILL : (byte)Verbs.DO); 
          else 
           tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WONT : (byte)Verbs.DONT); 
          tcpSocket.GetStream().WriteByte((byte)inputoption); 
          break; 
         default: 
          break; 
        } 
        break; 
       default: 
        sb.Append((char)input); 
        break; 
      } 
     } 
    } 
    } 
} 

在此先感謝您的幫助!

+0

我從https://www.nuget.org/packages/Telnet(https://github.com/9swampy上的代碼)獲得了源自minimalistic(已被修改爲按需要工作)的NuGet包/ Telnet /),如果你還沒有排序,可能會有所幫助... – 9swampy

回答

0

這是一個長期的問題。首先我會看看下面網站上的例子。它們使用套接字,並且可以用繼承套接字類(如tcpclient或tcplistener)的任何類來替換。我將使用您的案例中的異步示例:https://msdn.microsoft.com/en-us/library/w89fhyex(v=vs.110).aspx

這裏是對問題的解答 1)首先關閉哪個超時會做什麼? 答案:等待一段固定的時間 2)是我的Form1中的連接本身和telnet.cs文件中的哪一個在發送命令之間的延遲? 答: a)如果沒有響應,則表單中的一個表示錯誤 b)telnet.cs中的一個用於確保在繼續之前接收完整的消息。可以通過在套接字偵聽器示例中將Read(異步方法)替換爲ansync事件來消除。

3)我該如何適當延遲登錄提示,但仍然保持過程的其餘部分快速運行。目前,當我更改超時變量時,它會使每個連接永遠持續下去。 回答:使用異步套接字示例

4)我可以不使用指定的超時並使用我自己的while循環,我甚至需要這樣做嗎? 答:使用異步插座例如

5)什麼是Telnet.cs文件與「oldTimeOutMs」,「TimeOutMs」和「LoginTimeOutMs」做 答:使用表單應用

復位定時器事件在這段代碼中使用計時器沒有任何問題,只要它不阻止代碼繼續進行,並且只用於觸發事件以指示什麼時候沒有發生。定時器代碼可以用一個異步事件來代替,而不是一個同步等待,它會阻止代碼處理其他消息。

+0

我認爲這個回覆需要一些時間來處理。我將看看您提供的有關實現異步套接字的示例。希望它對我有意義! – Konan

+0

所以我需要用telnet.cs文件中的公共字符串Read()替換與您鏈接的異步版本相同的版本。你願意提供一個例子來幫助解決這個問題嗎?我使用了異步命令,但只有少量。 – Konan

+0

嘗試使用示例代碼。如有必要,將協助。 – jdweng