【问题标题】:Telnet/TcpClient C# Skipping Code and not iterating through loopTelnet/TcpClient C# 跳过代码而不是循环遍历
【发布时间】:2014-06-26 23:34:17
【问题描述】:

这听起来很傻,但由于某种原因,这段代码似乎跳过了阅读。或者,也许它发展得太快了?我正在尝试从服务器获取 telnet 响应,但我得到了第一行响应,但仅此而已。我放了多少 readline() 或者我是否尝试让线程休眠都没关系。我该怎么做才能从要打印的服务器获得整个响应?我想我把问题缩小到退出。在示例程序中,如果您对出口进行硬编码,它将立即结束循环并且不显示任何内容。我尝试让线程休眠,但这似乎停止了一切。

输出:

220 server-12.tower-558.messagelabs.com ESMTP

预期输出:

250-server-11.tower-555.messagelabs.com says EHLO to iphere
250-PIPELINING
250-8BITMIME
250-STARTTLS

我的代码:

 //Telnet Start
 IPHostEntry hostInfo = Dns.Resolve(list[j]);
 TelnetConnection tc = new TelnetConnection(hostInfo.AddressList[0].ToString(), 25);
 string prompt = "a";
 string consoleout = "";
 // while connected
 while (tc.IsConnected && prompt != "exit")
 {
 // display server output
 prompt = "ehlo a.com";
 tc.WriteLine(prompt);
 //I've tried adding a 2 or 5 second thread sleep here and I still get the same result.
 Console.Write(tc.Read());
 prompt = "exit";
 }
 //Telnet End

TelnetConnection 类:

// minimalistic telnet implementation
// conceived by Tom Janssens on 2007/06/06  for codeproject
//
// http://www.corebvba.be



using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;

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

    enum Options
    {
        SGA = 3
    }

    class TelnetConnection
    {
        TcpClient tcpSocket;

        int TimeOutMs = 100;

        public TelnetConnection(string Hostname, int Port)
        {
            try
            {
                tcpSocket = new TcpClient(Hostname, Port);
            }
            catch (SocketException e)
            {
                Console.Write(e);
            }

        }

        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;
                }
            }
        }
    }
}

更新:

使用下面的循环,我能够让它工作一次,但只有一次,当我验证 j 为 2 时,它不会遍历 j 的计数。我的输出、预期输出和函数如下。

功能:

for (int j = 0; j < list.Count; j++)
{
//Telnet Start
Console.WriteLine("On round #" + j);
IPHostEntry hostInfo = Dns.Resolve(list[j]);
TelnetConnection tc = new TelnetConnection(hostInfo.AddressList[0].ToString(), 25);
string prompt = "a";
string consoleout = "";
// while connected
while (tc.IsConnected && prompt != "exit")
{
// display server output
Console.Write(tc.Read());

// send client input to server
prompt = "ehlo a.com";
tc.WriteLine(prompt);

// display server output
consoleout = tc.Read();
Console.Write(consoleout);

//send exit input to server
prompt = "exit";
tc.WriteLine(prompt);
Console.Write(tc.Read());
}
Console.WriteLine("**DISCONNECTED**");
//Telnet End
if (consoleout.IndexOf("STARTTLS")>-1)
{
if (j == 0)
{
if (list[j].Contains(domains[i]))
dataGridView1.Rows.Add(domains[i], list[j], "Y", numberemployees, "Y");
else
dataGridView1.Rows.Add(domains[i], list[j], "Y", numberemployees, "N");
}
else
{
if (list[j].Contains(domains[i]))
dataGridView1.Rows.Add(null, list[j], "Y", null, "Y");
else
dataGridView1.Rows.Add(null, list[j], "Y", null, "N");
}
}
else
{
if (j == 0)
{
if (list[j].Contains(domains[i]))
dataGridView1.Rows.Add(domains[i], list[j], "N", numberemployees, "Y");
else
dataGridView1.Rows.Add(domains[i], list[j], "N", numberemployees, "N");
}
else
{
if (list[j].Contains(domains[i]))
dataGridView1.Rows.Add(null, list[j], "N", null, "Y");
else
dataGridView1.Rows.Add(null, list[j], "N", null, "N");
}
}

}

输出:

On round #0
True220 server-6.tower-95.messagelabs.com ESMTP
250-server-6.tower-95.messagelabs.com
250-STARTTLS
250-PIPELINING
250 8BITMIME
502 unimplemented (#5.5.1)
**DISCONNECTED**
On round #1
True220 server-14.tower-558.messagelabs.com ESMTP
**DISCONNECTED**

预期输出:

On round #0
True220 server-6.tower-95.messagelabs.com ESMTP
250-server-6.tower-95.messagelabs.com
250-STARTTLS
250-PIPELINING
250 8BITMIME
502 unimplemented (#5.5.1)
**DISCONNECTED**
On round #1
True220 server-14.tower-558.messagelabs.com ESMTP
250-STARTTLS
250-PIPELINING
250 8BITMIME
**DISCONNECTED**

所以无论出于何种原因,它根本不会执行第二个循环。但它也开始依赖于服务器。有些服务器会响应一些信息,而有些我会得到类似的信息,这看起来就像什么都没发生。

On round #0
True220 SMTP Proxy Server Ready
**DISCONNECTED**
On round #1
True220 SMTP Proxy Server Ready
**DISCONNECTED**
On round #2
True220 SMTP Server Ready
**DISCONNECTED**
On round #3
True220 SMTP Server Ready
**DISCONNECTED**
On round #4
True220 SMTP Proxy Server Ready
**DISCONNECTED**
On round #5
True220 SMTP Proxy Server Ready
**DISCONNECTED**

【问题讨论】:

  • 尝试执行var response = tc.Read(); 之类的操作,然后在其上设置断点以帮助找出问题出在哪里。
  • 好的,第一次通过它确实包含:“220 server-10.tower-555.messagelabs.com ESMTP\r\n”。当它第二次通过时,它包含一个空字符串。它似乎仍然停留在服务器响应的第一行。
  • 你的错误处理很奇怪。如果出现错误,您什么也不做。这几乎是不合适的。
  • 您不能那样使用“可用”。研究,它做了什么以及为什么它几乎总是一个错误。
  • 有货吗?你是在说我的 try catch 异常块吗?我试图捕捉并查看它,这样我就可以看到出了什么问题。

标签: c# loops telnet tcpclient


【解决方案1】:

凯尔,

看来你需要打开socket:

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

它没有打开,所以它正在返回。

[更新]

尝试在//Telnet Start 评论之前循环遍历IPHostEntry hostInfo = Dns.Resolve(list[j]);

private const int PORT25 = 25; // I hate magic numbers

foreach (var item in list) {
  var hostInfo = Dns.Resolve(item);
  Console.WriteLine(hostInfo);
  foreach (var address in hostInfo.AddressList) {
    var tc = new TelnetConnection(address, PORT25);
    Console.WriteLine("{0} TelnetConnection Connected: {1}", address, tc.IsConnected);
  }
}

[更新 2]

这真的很难调试,不知道您要连接的所有内容以及正在发生的其他事情。

也就是说,让我们尝试以下方法:

在你的类MinimalisticTelnet中,添加这个方法:

public void Close() {
    if (tcpSocket != null) {
        tcpSocket.Close();
    }
}

我在其他任何地方都看不到它,这可能会在您下次尝试第二次连接时导致一些问题。

现在,在您的测试代码中,在 while 循环之后添加新的一行代码

while (tc.IsConnected && prompt != "exit") {
    // display server output
    Console.Write(tc.Read());

    // send client input to server
    prompt = "ehlo a.com";
    tc.WriteLine(prompt);

    // display server output
    consoleout = tc.Read();
    Console.Write(consoleout);

    //send exit input to server
    prompt = "exit";
    tc.WriteLine(prompt);
    Console.Write(tc.Read());
}
tc.Close();
Console.WriteLine("**DISCONNECTED**");

幸运的是,您的第二次连接失败的原因是您仍然有一个打开的连接。

【讨论】:

  • 感谢您的回复,但只是为了澄清一下,这不是 TelnetConnection 功能中发生的事情吗?我对套接字也完全陌生,所以我该如何打开它?
  • 是的,但是在您为 TelnetConnection 类发布的代码中,没有任何东西会打开套接字。而不是return null; - 告诉它连接。
  • 好的,但是如果我添加它,我会得到: System.Net.Sockets.SocketException (0x80004005): A connect request was made on an already connected socket
  • 另外验证我保留了 try catch 块并添加了 Console.Write(tcpSocket.Connected);返回 true。
  • 尝试添加错误检查(就像我添加的抛出异常)。如果你通过它,你就知道你已经连接了。
【解决方案2】:

我解决了一个非常相似的问题,添加 3 次读取,然后 8 秒超时,最后再次读取并在我的 RICHTEXBOX 中显示:


字符串 r1 = conexion.Read();

字符串 r2 = conexion.Read();

字符串 r3 = conexion.Read();

System.Threading.Thread.Sleep(8000);

richtextbox.AppendText(r1 + r2 + r3);


希望对你有帮助!

告诉我它是否适合你。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-26
    相关资源
    最近更新 更多