我有一个服务器net.Conn,我想在读取字节之前先查看一下它,以检查它是客户端尝试使用的纯文本协议还是SSL / TLS。
net.Conn
检查http://golang.org/pkg/net/,似乎该Conn界面没有类似的内容。我知道我可以使用iobuf.Reader,但是我想通过TLS Conn来tls.Conn(conn, config)证明客户端使用的是SSL / TLS,并且iobuf.Reader可以从原始目录中读取Conn,因此握手tls.Conn将失败。
Conn
iobuf.Reader
tls.Conn(conn, config)
tls.Conn
那么,有什么方法可以窥探ConnGo语言(类似于MSG_PEEKC / C ++套接字)吗?或者,在tls.Conn从底层读取前几个字节后创建一个Conn?
MSG_PEEK
您已经很接近解决方案了- 唯一出错的地方Conn就是首先阅读本身。你是正确的bufio.Reader的Peek方法是要走的路。诀窍是首先使缓冲的读取器生效,然后调用Peek缓冲的读取器,而不是从原始读取器进行读取Conn。这是一种bufferedConn可以满足您需要的类型:
bufio.Reader
Peek
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) }
这样做是允许你访问所有的正常net.Conn方法(通过嵌入net.Conn-你也可以写的包装功能,但是这是一个极大的方便,更清洁),并另外提供访问bufferedReader的Peek和Read方法(这一点很重要ReadBE在上调用bufferedReader,而不是直接在上调用,net.Conn因为Peek将数据存储在缓冲区中,因此后续调用Read需要能够首先从该缓冲区中读取任何数据,然后再返回基础net.Conn)。
bufferedReader
Read
newBufferedConnSize鉴于当前的默认缓冲区大小为4096字节,该函数可能是不必要的,但是从技术上讲,如果您要依赖能够以Peek给定大小进行调用并且不让它返回错误(特别是ErrBufferFull),则应显式设置它的大小至少要与您打算窥视的字节数一样大。
newBufferedConnSize
ErrBufferFull
在Go Playground上检查一下。