mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-10-20 23:39:55 +08:00
95 lines
3.2 KiB
Go
95 lines
3.2 KiB
Go
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
|
||
}
|