【问题标题】:How to read data from Telnet session如何从 Telnet 会话中读取数据
【发布时间】:2020-03-25 18:33:55
【问题描述】:

我正在尝试创建一个工具来通过 Telnet 连接到网络设备并使用 go-telnet 发送一些命令(具有某些附加要求的类似预期)。

直到我设法创建连接并使用以下命令发送命令:

func main() {
    var loginBuffer = [6]byte{'r', 'o', 'o', 't', '\r', '\n'}
    var login = loginBuffer[:]

    conn, err := telnet.DialTo("10.10.10.2:23")
    if nil != err {
        fmt.Println(err)
    }
    defer conn.Close()

    conn.Write(login)
}

使用 Wireshark 我可以看到设备响应,但是我无法读取任何响应数据。猜猜我以错误的方式使用 Read(),不确定。

希望有一个工作示例或说明如何在这种情况下捕获和处理响应数据。

【问题讨论】:

    标签: go telnet


    【解决方案1】:

    您的连接读取操作在哪里? 我认为您需要调用 conn.read(buffer) 从连接中读取并将其写入缓冲区

    https://godoc.org/github.com/reiver/go-telnet#Conn.Read
    

    这些示例对您正在使用的 hte 包没有多大帮助。可能以下从不同的 telnet go 包中取出的示例会更有帮助。

    https://github.com/ziutek/telnet/blob/master/examples/unix-cisco/main.go
    

    【讨论】:

    • 这正是我所做的,但是执行在 conn.Read() 处“挂起”,就好像期望收到某些东西却从未收到一样。说实话,我什至无法想象如何处理它=(
    • @Alexander, ...那么为什么您决定不将这段代码包含在您的问题中?您基本上已经询问了为什么某些东西在没有显示“某物”真正是什么的情况下不起作用。请展示一个完整的不工作的部分。理想情况下,查看设备发送的数据会很酷(将其与您所做的相关联。)
    • @kostix 对此感到抱歉,因为我尝试了大约十种不同的选项,但都没有奏效,我不确定该发布哪一个。
    【解决方案2】:

    感谢大家抽空回答我的问题。我设法确定了问题:

    1. 每次我创建一个读取缓冲区时它都太大(1024 字节),所以程序正在等待它填满。现在我正在使用循环读取 1 字节缓冲区。

    2. 看来,我还需要一些标准来让函数停止读取并继续发送命令。

    这是工作代码:

    // Thin function reads from Telnet session. "expect" is a string I use as signal to stop reading
    func ReaderTelnet(conn *telnet.Conn, expect string) (out string) {
        var buffer [1]byte
        recvData := buffer[:]
        var n int
        var err error
    
        for {
            n, err = conn.Read(recvData)
            fmt.Println("Bytes: ", n, "Data: ", recvData, string(recvData))
            if n <= 0 || err != nil || strings.Contains(out, expect) {
                break
            } else {
                out += string(recvData)
            }
        }
        return out
    }
    
    //convert a command to bytes, and send to Telnet connection followed by '\r\n' 
    func SenderTelnet(conn *telnet.Conn, command string) {
        var commandBuffer []byte
        for _, char := range command {
            commandBuffer = append(commandBuffer, byte(char))
        }
    
        var crlfBuffer [2]byte = [2]byte{'\r', '\n'}
        crlf := crlfBuffer[:]
    
        fmt.Println(commandBuffer)
    
        conn.Write(commandBuffer)
        conn.Write(crlf)
    }
    
    func main() {
        conn, err := telnet.DialTo("10.10.10.2:23")
        if nil != err {
            fmt.Println(err)
        }
    
        fmt.Print(ReaderTelnet(conn, "Login"))
        SenderTelnet(conn, "root")
        fmt.Print(ReaderTelnet(conn, "Password"))
        SenderTelnet(conn, "root")
        fmt.Print(ReaderTelnet(conn, ">"))
    }
    

    【讨论】:

    • 我想我现在明白了。好吧,在读取与操作系统维护的套接字缓冲区中可用的字节数一样多的字节后,在套接字上读取会返回。所以读取长度为 1024 的切片应该没问题——读取 1 到 1024 个字节。如果那个 Telnet 包提供的连接工作方式不同,那就是其中的一个错误。现在,据我了解,您的设备实现了文本协议。最好使用“逐行”处理来处理此类协议;在您的情况下,一行是由 CRLF 序列终止的任意数量的字节。
    • ...要解决这个问题,首先将您的 Conn 包装在 bufio.Reader 中,然后使用它的 ReadLine 或 ReadBytes 方法来读取完整的行。
    • 谢谢亚历山大的例子。只是一个问题:我注意到如果(例如)“登录”字符串从未出现并且输入流结束此语句将永远等待:n, err = conn.Read(recvData) 有人注意到这种行为吗?我尝试玩 time.AfterFunc 函数但没有成功。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    • 2014-05-05
    • 1970-01-01
    • 2014-05-13
    • 2011-08-27
    • 2017-04-21
    • 1970-01-01
    相关资源
    最近更新 更多