偷看康恩而不读书

时间:2014-10-04 20:20:41

标签: sockets networking go peek

我有一个服务器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

1 个答案:

答案 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上查看。