duanlou2917 2018-06-26 17:11
浏览 188
已采纳

从SSH会话Golang读取数据

I posted a similar question here for reading from a telnet session.

I am trying to read data from an SSH session in golang. I wrote the following functions to try to accomplish this.

I was running into an issue where I was trying to read from stdout and it was empty and it caused my program to lock. To try to work around this I wrote BufferSocketData, it checks the channel ReadDataFromSocket is supposed to append to and if it has data it adds it to the buffer. If after 1 second it still hasn't received any data it stops the read.

This isn't working correctly though and I'm unsure why. Only the first read gets new data subsequent reads return an empty string even if there is data in the buffer.

In my previous question I was able to use SetReadDeadline to limit the amount of time reading from the socket, is there something similar I can use with an SSH session? or do I need to use a different strategy all together?

/*
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
    }
}

Please let me know if you need any other information.

  • 写回答

1条回答 默认 最新

  • dpwtr666638 2018-06-26 19:02
    关注

    Start a single reader goroutine for the session. This goroutine reads from the session and sends data to a channel.

    In the main goroutine, select in a loop with cases for data received and timeout. Process each case as appropriate.

    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
            }
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?