Files
v2ray_simple/utils/multi.go

95 lines
3.2 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 utils
import "log"
// 该 MultiReader 的用例请参照 netLayer.ReadFromMultiReader , 在 netLayer/readv.go中
//具体实现见 readv_*.go; 用 GetReadVReader() 函数来获取本平台的对应实现。
type MultiReader interface {
Init([][]byte)
Read(fd uintptr) int32
Clear()
}
// 因为 net.Buffers 的 WriteTo方法只会查看其是否实现了net包私有的 writeBuffers 接口
// 我们无法用WriteTo来给其它 代码提升性能;因此我们重新定义一个新的借口, 实现了 MultiWriter
// 接口的结构 我们就认为它会提升性能,比直接用 net.Buffers.WriteTo 要更强.
/*
本接口 在代理中的用途,基本上只适合 加密层 能够做到分组加密 的情况; 因为如果不加密的话就是裸协议直接就splice或者writev了,也不需要这么麻烦;
如果是tls的话可能涉及自己魔改tls把私有函数暴露出来然后分组加密
如果是vmess的话倒是有可能的不过我还没研究vmess的 加密细节;
而如果是ss 那种简单混淆 异或加密的话,则是完全可以的
分组加密然后 一起用 writev 发送出去,可以降低网络延迟, 不过writev性能的提升可能是非常细微的, 也不必纠结这里.
如果考虑另一种情况,即需要加包头和包尾,则区别就很大了;
WriteTo会调用N次Write如果包装的话会包装N 个包头和 包尾而如果我们实现WriteBuffers方法
只需先写入包头,而在 最后一个 []byte 后加 包尾,那么就可以获得性能提升,
我们只需增添两个新的 []byte 放在其前后即可, 然后再用 writev 一起发送出去
那么实际上 websocket 的gobwas/ws 包在不开启缓存时,就是 每次Write都写一次包头的情况;
所以websocket很有必要实现 WriteBuffers 方法.
目前实现 的有 vless.UserConn 和 ws.Conn
*/
type MultiWriter interface {
WriteBuffers([][]byte) (int64, error)
}
func BuffersLen(bs [][]byte) (allnum int) {
if len(bs) < 1 {
return 0
}
for _, b := range bs {
allnum += len(b)
}
return allnum
}
func PrintBuffers(bs [][]byte) {
for i, b := range bs {
log.Println(i, b)
}
}
// 如果 分配了新内存来 包含数据,则 duplicate ==true; 如果利用了原有的第一个[]byte, 则 duplicate==false
// 如果 duplicate==false, 不要 使用 PutPacket等方法放入Pool
// 因为 在更上级的调用会试图去把 整个bs 放入pool;
func MergeBuffers(bs [][]byte) (result []byte, duplicate bool) {
if len(bs) < 1 {
return
}
b0 := bs[0]
if len(bs) == 1 {
return b0, false
}
allLen := BuffersLen(bs)
if allLen <= cap(b0) { //所有的长度 小于第一个的cap那么可以全放入第一个中;实际readv不会出现这种情况
b0 = b0[:allLen]
cursor := len(b0)
for i := 1; i < len(bs); i++ {
cursor += copy(b0[cursor:], bs[i])
}
return b0, false
}
if allLen <= MaxBufLen {
result = GetPacket()
} else {
result = make([]byte, allLen) //实际目前的readv实现也很难出现这种情况, 默认16个1500是不会出这种情况的
}
cursor := 0
for i := 0; i < len(bs); i++ {
cursor += copy(result[cursor:], bs[i])
}
return result[:allLen], true
}