使用golang诊断来自unix socket的非常慢的读取(netcat中1分钟vs 1秒)

时间:2018-03-12 15:14:29

标签: go unix-socket

背景 我正在编写一些软件包来与OpenVas漏洞扫描程序进行通信 - 扫描程序使用一些不同的协议进行通信 - 都是由通过unix套接字或tcp连接发送的xml或文本字符串组成的(即使是使用unix套接字)。

我遇到的问题是OTP协议(OpenVas内部协议没有详细记录)

我可以使用netcat运行以下命令,我将在一秒钟内收到回复:

  

echo -en'< OTP / 2.0> \ nCLIENT< |> NVT_INFO \ n' | ncat -U   /var/run/openvassd.sock

这导致一个相当大的响应,在终端中看起来像这样:

< OTP/2.0 >
SERVER <|> NVT_INFO <|> 201802131248 <|> SERVER
SERVER <|> PREFERENCES <|>
cache_folder <|> /var/cache/openvas
include_folders <|> /var/lib/openvas/plugins
max_hosts <|> 30
//lots more here

例如,我以前有一些这样的代码用于阅读回复:

func (c Client) read() ([]byte, error) {

    // set up buffer to read in chunks
    bufSize := 8096
    resp := []byte{}
    buf := make([]byte, bufSize)

    for {
        n, err := c.conn.Read(buf)
        resp = append(resp, buf[:n]...)
        if err != nil {
            if err != io.EOF {
                return resp, fmt.Errorf("read error: %s", err)
            }
            break
        }
        fmt.Println("got", n, "bytes.")

    }
    fmt.Println("total response size:", len(resp))

    return resp, nil
}

我得到了完整的结果,但它是小块的(我猜是逐行)所以我看到的输出是这样的(在显示完整响应之前的一分钟左右):

got 53 bytes.
got 62 bytes.
got 55 bytes.
got 62 bytes.
got 64 bytes.
got 59 bytes.
got 58 bytes.
got 54 bytes.
got 54 bytes.
got 54 bytes.
got 64 bytes.
got 59 bytes.
... (more)

所以我决定尝试ioutil.ReadAll:

func (c Client) read() ([]byte, error) {
    fmt.Println("read start")
    d, err := ioutil.ReadAll(c.conn)
    fmt.Println("read done")
    return d, err
}

这会再次返回完整的响应,但是&#34; read start&#34;之间的时间。和#34;完成阅读&#34;与&lt;大约一分钟相比。该命令预计需要1秒。

与netcat相比,通过golang读取的原因有什么想法 - 我如何诊断/解决问题?**

1 个答案:

答案 0 :(得分:2)

似乎服务正在等待更多输入,并且最终在一分钟后超时。在CLI示例中,一旦echo命令完成,管道的一侧将关闭以进行写入,在这种情况下,服务将通过0长度的recv通知。

为了在Go中执行相同操作,您需要在完成发送命令后在net.UnixConn上调用CloseWrite

c.conn.(*net.UnixConn).CloseWrite()