You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 12:37:42