如何为net.Conn结构体添加自定义字节或创建包含自定义字节的新net.Conn
如何为net.Conn结构体添加自定义字节或创建包含自定义字节的新net.Conn
嘿,我来帮你搞定这个需求!首先得纠正一个关键误区:net.Conn是Go标准库中的接口,不是可直接实例化的结构体,所以你代码里net.Conn{buff: data}这种写法是不成立的。不过要实现「在代理两个连接时插入自定义数据」的目标,我们可以通过包装net.Conn接口的方式来实现,下面给你两种实用的方案:
方案一:在现有连接前插入自定义数据(适用于代理场景)
这个方案会创建一个自定义的Conn包装器,当读取该Conn时,会先返回你预设的自定义字节,之后再转发原连接的真实数据,非常适合你提到的transport代理函数场景。
首先定义我们的自定义Conn类型:
import ( "io" "net" "sync" "time" ) // CustomConn 包装net.Conn,用于插入自定义前置数据 type CustomConn struct { originalConn net.Conn // 原始连接 prefixData []byte // 要插入的自定义数据 readOffset int // 当前读取自定义数据的偏移量 mu sync.Mutex // 保证并发安全 } // NewCustomConn 创建一个带有前置自定义数据的连接 func NewCustomConn(conn net.Conn, prefix []byte) *CustomConn { return &CustomConn{ originalConn: conn, prefixData: prefix, } } // Read 实现net.Conn的Read方法:先读自定义数据,再读原始连接数据 func (c *CustomConn) Read(b []byte) (n int, err error) { c.mu.Lock() defer c.mu.Unlock() // 如果自定义数据还没读完,先返回这部分数据 if c.readOffset < len(c.prefixData) { bytesToCopy := len(b) remaining := len(c.prefixData) - c.readOffset if remaining < bytesToCopy { bytesToCopy = remaining } copy(b, c.prefixData[c.readOffset:c.readOffset+bytesToCopy]) c.readOffset += bytesToCopy return bytesToCopy, nil } // 自定义数据读完后,转发原始连接的读取 return c.originalConn.Read(b) } // 以下是net.Conn接口需要实现的其他方法,直接转发给原始连接即可 func (c *CustomConn) Write(b []byte) (n int, err error) { return c.originalConn.Write(b) } func (c *CustomConn) Close() error { return c.originalConn.Close() } func (c *CustomConn) LocalAddr() net.Addr { return c.originalConn.LocalAddr() } func (c *CustomConn) RemoteAddr() net.Addr { return c.originalConn.RemoteAddr() } func (c *CustomConn) SetDeadline(t time.Time) error { return c.originalConn.SetDeadline(t) } func (c *CustomConn) SetReadDeadline(t time.Time) error { return c.originalConn.SetReadDeadline(t) } func (c *CustomConn) SetWriteDeadline(t time.Time) error { return c.originalConn.SetWriteDeadline(t) }
接下来你就可以在transport函数中使用这个自定义Conn了,比如要给src连接插入自定义数据:
var data = []byte("Hello") // 假设你已经有了真实的srcConn和dstConn srcConn, _ := net.Dial("tcp", "example.com:80") dstConn, _ := someListener.Accept() // 这里替换成你实际的目标连接 // 创建带有自定义数据的包装连接 customSrc := NewCustomConn(srcConn, data) // 传入transport函数,此时dst会先收到"Hello",再收到srcConn的原始数据 transport(customSrc, dstConn)
方案二:创建仅包含自定义数据的模拟Conn
如果你只是想创建一个完全由自定义字节构成的net.Conn(不需要依赖真实网络连接),可以基于bytes.Buffer来实现:
import ( "bytes" "net" "time" ) // BufferConn 基于bytes.Buffer的模拟net.Conn type BufferConn struct { buf *bytes.Buffer } func NewBufferConn(data []byte) *BufferConn { return &BufferConn{ buf: bytes.NewBuffer(data), } } func (b *BufferConn) Read(p []byte) (n int, err error) { return b.buf.Read(p) } func (b *BufferConn) Write(p []byte) (n int, err error) { return b.buf.Write(p) } func (b *BufferConn) Close() error { // 模拟关闭,这里可以留空或者做清理 return nil } func (b *BufferConn) LocalAddr() net.Addr { // 返回一个模拟的地址 return &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0} } func (b *BufferConn) RemoteAddr() net.Addr { return &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0} } func (b *BufferConn) SetDeadline(t time.Time) error { return nil } func (b *BufferConn) SetReadDeadline(t time.Time) error { return nil } func (b *BufferConn) SetWriteDeadline(t time.Time) error { return nil }
使用示例:
var data = []byte("Hello") conn := NewBufferConn(data) // 现在这个conn可以直接传入需要net.Conn的函数中 transport(conn, dstConn)
备注:内容来源于stack exchange,提问作者simoninstring
相关产品推荐
相关产品推荐

