Files
v2ray_simple/netLayer/readv.go
e1732a364fed f28f0d0bee 修订代码, 默认loglevel 改为 Log_info.
对一般用户而言,还是需要使用Info等级 来了解一下 一般的 日志情况,等到使用熟练之后,且确认运行没有错误后, 可以自行调为 warning 来提升性能

发现 bubble包 还自己引入了 命令行参数,这十分不可取,所以我们还是直接使用其代码。

将其它包中 的 命令行参数 统一 移动 到 cmd/verysimple 中;tls lazy 特性因为还在 调试阶段,所以 命令行参数 仍然放到 v2ray_simple 包中。
2022-04-26 13:22:18 +08:00

170 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package netLayer
import (
"io"
"net"
"sync"
"syscall"
"github.com/e1732a364fed/v2ray_simple/utils"
)
//经过测试网速越快、延迟越小越不需要readv, 此时首包buf越大越好, 因为一次系统底层读取就会读到一大块数据, 此时再用readv分散写入 实际上就是反效果; readv的数量则不需要太多
//在内网单机自己连自己测速时,readv会导致降速.
const (
readv_buffer_allocLen = 8
ReadvSingleBufLen = 4096
DefaultReadvOption = true
)
var (
// readv pool, 缓存 mr和buffers进一步减轻内存分配负担
readvPool sync.Pool
UseReadv bool
)
func init() {
readvPool = sync.Pool{
New: newReadvMem,
}
//预先放进去两个
readvPool.Put(newReadvMem())
readvPool.Put(newReadvMem())
}
// 缓存 readvMem 以及对应分配的系统相关的 utils.SystemReadver.
// 使用 readvMem的最大好处就是 buffers 和 mr 都是不需要 释放的.
// 因为不需释放mr, 所以也就节省了多次 mr.Init 的开销.
// 该 readvMem 以及 readvPool 专门服务于 TryCopy 函数.
type readvMem struct {
buffers [][]byte
mr utils.SystemReadver
}
func allocReadvBuffers(mr utils.SystemReadver, len int) [][]byte {
bs := make([][]byte, len)
for i := range bs {
// 这里单独make而不是从 其它pool中获取, 这样可以做到专用
bs[i] = make([]byte, ReadvSingleBufLen)
}
mr.Init(bs, ReadvSingleBufLen)
return bs
}
func newReadvMem() any {
mr := utils.GetReadVReader()
return &readvMem{
mr: mr,
buffers: allocReadvBuffers(mr, readv_buffer_allocLen),
}
}
func get_readvMem() *readvMem {
return readvPool.Get().(*readvMem)
}
//将创建好的rm放回 readvPool
func put_readvMem(rm *readvMem) {
rm.buffers = utils.RecoverBuffers(rm.buffers, readv_buffer_allocLen, ReadvSingleBufLen)
readvPool.Put(rm)
}
/*
//目前我们使用内存池,所以暂时不需要手动释放内存,
//如果真需要手动申请、释放,可参考 https://studygolang.com/articles/9721
func (rm *readvMem) destroy() {
rm.mr.Clear()
rm.mr = nil
rm.buffers = nil
}*/
/* readvFrom 用于读端实现了 readv但是写端的情况比如 从socks5读取 数据, 等裸协议的情况。
若 rm 未给出,会使用 get_readvMem 来初始化 缓存。
返回错误时,依然会返回 原buffer 或者 在函数内部新分配的buffer.
本函数不负责 释放分配的内存. 因为有时需要重复利用缓存。
小贴士:将该 [][]byte 写入io.Writer的话只需使用 net.Buffers.WriteTo方法, 即可自动适配writev。
不过实测writev没什么太大效果还会造成不稳定。因为 WriteTo会篡改cap
TryCopy函数使用到了本函数 来进行readv相关操作。
*/
func readvFrom(rawReadConn syscall.RawConn, rm *readvMem) ([][]byte, error) {
if rm == nil {
rm = get_readvMem()
}
allocedBuffers := rm.buffers
var nBytes uint32
err := rawReadConn.Read(func(fd uintptr) bool {
n, e := rm.mr.Read(fd)
if e != nil {
return false
}
nBytes = n
return true
})
if err != nil {
return allocedBuffers, err
}
if nBytes == 0 {
return allocedBuffers, io.EOF
}
nBuf := utils.ShrinkBuffers(allocedBuffers, int(nBytes), ReadvSingleBufLen)
return allocedBuffers[:nBuf], nil
}
//依次试图使用 readv、ReadBuffers 以及 原始 Read 读取数据
func ReadBuffersFrom(c io.Reader, rawReadConn syscall.RawConn, mr utils.MultiReader) (buffers [][]byte, err error) {
if rawReadConn != nil {
readv_mem := get_readvMem()
defer put_readvMem(readv_mem)
buffers, err = readvFrom(rawReadConn, readv_mem)
} else if mr != nil {
return mr.ReadBuffers()
} else {
packet := utils.GetPacket()
var n int
n, err = c.Read(packet)
if err != nil {
return
}
buffers = append(buffers, packet[:n])
}
return
}
func IsConnGoodForReadv(c net.Conn) (r int, rawReadConn syscall.RawConn, mr utils.MultiReader) {
rawReadConn = GetRawConn(c)
var ok bool
if rawReadConn != nil {
r = 1
return
} else if mr, ok = c.(utils.MultiReader); ok {
r = 2
return
}
return
}