偷看康恩而不读书

ldx*_*ldx 4 sockets networking go peek

我有一个服务器net.Conn,我想在读出字节之前查看它,检查它是否是客户端尝试使用的纯文本协议,或SSL/TLS.

检查http://golang.org/pkg/net/,似乎Conn界面没有这样的东西.我知道我可以使用一个iobuf.Reader,但是tls.Conn(conn, config)如果事实证明客户端正在使用SSL/TLS并且iobuf.Reader将从原始读取,那么我想获得TLS Conn Conn,因此握手tls.Conn将失败.

那么有什么方法可以窥探ConnGo(就像MSG_PEEK在C/C++套接字中那样)?或者,tls.Conn在我从底层读出前几个字节后创建一个Conn

jos*_*hlf 12

你非常接近一个解决方案 - 你唯一错的Conn就是首先从自身读取.你是正确的bufio.ReaderPeek方法是要走的路.诀窍是首先制作缓冲读卡器并调用Peek缓冲读卡器,而不是从原件读取Conn.这是一种bufferedConn可以满足您需求的类型:

type bufferedConn struct {
    r        *bufio.Reader
    net.Conn // So that most methods are embedded
}

func newBufferedConn(c net.Conn) bufferedConn {
    return bufferedConn{bufio.NewReader(c), c}
}

func newBufferedConnSize(c net.Conn, n int) bufferedConn {
    return bufferedConn{bufio.NewReaderSize(c, n), c}
}

func (b bufferedConn) Peek(n int) ([]byte, error) {
    return b.r.Peek(n)
}

func (b bufferedConn) Read(p []byte) (int, error) {
    return b.r.Read(p)
}
Run Code Online (Sandbox Code Playgroud)

这样做可以让你访问所有常规net.Conn方法(通过嵌入net.Conn- 你也可以编写包装函数,但这更容易和更清洁),并且还提供对bufferedReaders PeekRead方法的访问(重要的Read是调用bufferedReader,而不是直接在net.Conn因为Peek存储缓冲区中的数据,所以后续调用Read需要能够先从这个缓冲区中读出任何数据然后再回到底层net.Conn).

newBufferedConnSize函数可能是不必要的,因为当前的默认缓冲区大小是4096字节,但从技术上讲,如果你将依赖于能够以Peek给定的大小调用而不是让它返回错误(具体而言ErrBufferFull),你应该明确地设置它大小至少与您想要查看的字节数一样大.

Go Playground查看.