【问题标题】:Reading Data from SSH Session Golang从 SSH 会话 Golang 中读取数据
【发布时间】:2018-06-27 03:02:41
【问题描述】:

我发布了一个类似的问题here 用于从 telnet 会话中阅读。

我正在尝试从 golang 中的 SSH 会话中读取数据。我编写了以下函数来尝试实现这一点。

我遇到了一个问题,我试图从 stdout 中读取,它是空的,它导致我的程序锁定。为了尝试解决这个问题,我编写了 BufferSocketData,它检查应该附加到的通道 ReadDataFromSocket,如果它有数据,它会将其添加到缓冲区中。如果 1 秒后仍未收到任何数据,则停止读取。

但这不能正常工作,我不确定为什么。即使缓冲区中有数据,也只有第一次读取会获得新数据,后续读取会返回空字符串。

在我之前的问题中,我能够使用 SetReadDeadline 来限制从套接字读取的时间量,我可以在 SSH 会话中使用类似的东西吗?还是我需要一起使用不同的策略?

/*
ReadDataFromSocket - Attempts to read any data in the socket.
*/
func ReadDataFromSocket(sock io.Reader, c chan string) {
    var recvData = make([]byte, 1024)
    var numBytes, _ = sock.Read(recvData)
    c <- string(recvData[:numBytes])
}

/*
BufferSocketData - Read information from the socket and store it in the buffer.
*/
func (s *SSHLib) BufferSocketData(inp chan string, out chan string) {
    var data string
    var timeout int64 = 1000 // 1 second timeout.
    var start = utils.GetTimestamp()

    for utils.GetTimestamp()-start < timeout {
        select {
        case data = <-inp:
        default:
        }
        if data != "" {
            break
        }
    }
    out <- data
}

/*
GetData - Start goroutines to get and buffer data.
*/
func (s *SSHLib) GetData() {
    var sockCh = make(chan string)
    var buffCh = make(chan string)

    go ReadDataFromSocket(s.Stdout, sockCh)
    go s.BufferSocketData(sockCh, buffCh)

    var data = <-buffCh

    if data != "" {
        s.Buffer += data
    }
}

如果您需要任何其他信息,请告诉我。

【问题讨论】:

  • GetData 是否被多次调用?
  • 是的,我有一个函数可以检查缓冲区中的正则表达式匹配,如果没有找到匹配并且没有发生超时,它会再次调用 GetData。
  • 每次调用 GetData 都会启动一个 goroutine 来读取连接,当 GetData 返回时,这些 goroutine 可以挂起。这些 goroutine 最终将读取数据,但数据将被忽略。描述你试图解决的更高层次的问题。您是否在 s.Buffer 上调用正则表达式匹配,直到找到匹配或超时?
  • 主要问题是我在初次调用 GetData 后从未获得任何新数据,我猜这与我的 go 例程和通道的使用有关。是的,如果在合理的时间内没有找到匹配项,我会检查 s.Buffer 以查看它是否匹配某些正则表达式或超时。

标签: go ssh


【解决方案1】:

为会话启动单个阅读器 goroutine。该 goroutine 从会话中读取数据并将数据发送到通道。

在主 goroutine 中,在循环中选择接收数据和超时的情况。酌情处理每个案例。

type SSHLib struct {
    Stdout io.Reader
    Buffer string
    Data   chan string  // <-- Add this member
}

// New creates a new SSHLib. This example shows the code 
// relevant to reading stdout only. 
func New() *SSHLib {
    s := &SSHLib{Data: make(chan string)}
    go s.Reader()
    return s
}

// Reader reads data from stdout in a loop.
func (s *SSHLib) Reader() {
    var data = make([]byte, 1024)
    for {
        n, err := s.Stdout.Read(data)
        if err != nil {
            // Handle error
            return
        }
        s.Data <- string(data[:n])
    }
}

// GetData receives data until regexp match or timeout.
func (s *SSHLib) GetData() {
    t := time.NewTimer(time.Second)
    defer t.Stop()
    for {
        select {
        case d := <-s.Data:
            s.Buffer += d
            // Check for regexp match in S.Buffer
        case <-t.C:
            // Handle timeout
            return
        }
    }
}

【讨论】:

  • 在这个例子中,如果以go s.Reader() 开始的goroutine 在n, err := s.Stdout.Read(data) 上阻塞,什么会清理它?
  • @RomanDodin 当应用程序关闭底层网络连接时,对s.Stdout.Read 的调用会立即返回错误。这是如何发生的不在问题的范围内。
猜你喜欢
  • 2011-06-09
  • 2011-08-27
  • 2020-03-25
  • 2017-04-21
  • 1970-01-01
  • 2018-12-25
  • 1970-01-01
  • 1970-01-01
  • 2013-07-03
相关资源
最近更新 更多