我有一个服务器net.Conn
,我想在读出字节之前查看它,检查它是否是客户端尝试使用的纯文本协议,或SSL / TLS。
检查http://golang.org/pkg/net/,似乎Conn
界面没有这样的内容。我知道我可以使用iobuf.Reader
,但如果结果客户端使用的是SSL / TLS,我想通过tls.Conn(conn, config)
获取TLS Conn,iobuf.Reader
会读取从原始Conn
开始,tls.Conn
中的握手将失败。
那么有什么方法可以窥探Go中的Conn
(类似于C / C ++套接字中的MSG_PEEK
)?或者,在我从基础tls.Conn
读出前几个字节后创建Conn
?
答案 0 :(得分:10)
你非常接近一个解决方案 - 你唯一错的就是首先从Conn
本身阅读。你是对的,bufio.Reader
的{{1}}方法是可行的。诀窍是首先制作缓冲读卡器并在缓冲读卡器上调用Peek
,而不是从原始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)
}
方法(通过嵌入net.Conn
- 你也可以编写包装函数,但这样更简单,更清洁),另外提供对net.Conn
的{{1}}和bufferedReader
方法的访问权限({1}}上Peek
调用Read
非常重要,而不是直接Read
因为bufferedReader
将数据存储在缓冲区中,因此对net.Conn
的后续调用需要能够先从此缓冲区中读取任何数据,然后再回退到基础Peek
)。
Read
函数可能是不必要的,因为当前的默认缓冲区大小是4096字节,但从技术上讲,如果你将依赖于能够以给定大小调用net.Conn
并且没有它返回一个错误(特别是ErrBufferFull
),你应该明确地将它设置为一个至少与你想要查看的字节数一样大的大小。
在Go Playground上查看。