mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-10-16 22:00:53 +08:00
完善对writev的支持;为vless和ws实现MultiWriter;修订代码
This commit is contained in:
14
main.go
14
main.go
@@ -977,7 +977,12 @@ func tryRawCopy(useSecureMethod bool, proxy_client proxy.UserClient, proxy_serve
|
|||||||
if tlsLayer.PDD {
|
if tlsLayer.PDD {
|
||||||
log.Println("SpliceRead R方向 退化……", wlcdc.R.GetFailReason())
|
log.Println("SpliceRead R方向 退化……", wlcdc.R.GetFailReason())
|
||||||
}
|
}
|
||||||
io.Copy(wrc, wlc)
|
if netLayer.UseReadv {
|
||||||
|
netLayer.TryCopy(wrc, wlc)
|
||||||
|
} else {
|
||||||
|
io.Copy(wrc, wlc)
|
||||||
|
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1084,7 +1089,12 @@ func tryRawCopy(useSecureMethod bool, proxy_client proxy.UserClient, proxy_serve
|
|||||||
if tlsLayer.PDD {
|
if tlsLayer.PDD {
|
||||||
log.Println("SpliceRead W方向 退化……", wlcdc.W.GetFailReason())
|
log.Println("SpliceRead W方向 退化……", wlcdc.W.GetFailReason())
|
||||||
}
|
}
|
||||||
io.Copy(wlc, wrc)
|
if netLayer.UseReadv { //就算不用splice, 一样可以用readv来在读那一端增强性能
|
||||||
|
netLayer.TryCopy(wlc, wrc)
|
||||||
|
} else {
|
||||||
|
io.Copy(wlc, wrc)
|
||||||
|
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,3 +7,18 @@ Package netLayer contains definitions in network layer AND transport layer.
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
package netLayer
|
package netLayer
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
func IsBasicConn(r interface{}) bool {
|
||||||
|
switch r.(type) {
|
||||||
|
case *net.TCPConn:
|
||||||
|
return true
|
||||||
|
case *net.UDPConn:
|
||||||
|
return true
|
||||||
|
case *net.UnixConn:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@@ -40,6 +40,13 @@ func TryCopy(writeConn io.Writer, readConn io.Reader) (allnum int64, err error)
|
|||||||
var mr utils.MultiReader
|
var mr utils.MultiReader
|
||||||
var buffers net.Buffers
|
var buffers net.Buffers
|
||||||
var rawConn syscall.RawConn
|
var rawConn syscall.RawConn
|
||||||
|
var isWriteConn_a_MultiWriter bool
|
||||||
|
var multiWriter utils.MultiWriter
|
||||||
|
isWriteConnBasic := IsBasicConn(writeConn)
|
||||||
|
|
||||||
|
if !isWriteConnBasic {
|
||||||
|
multiWriter, isWriteConn_a_MultiWriter = writeConn.(utils.MultiWriter)
|
||||||
|
}
|
||||||
|
|
||||||
if utils.CanLogDebug() {
|
if utils.CanLogDebug() {
|
||||||
log.Println("TryCopy", reflect.TypeOf(readConn), "->", reflect.TypeOf(writeConn))
|
log.Println("TryCopy", reflect.TypeOf(readConn), "->", reflect.TypeOf(writeConn))
|
||||||
@@ -67,17 +74,29 @@ func TryCopy(writeConn io.Writer, readConn io.Reader) (allnum int64, err error)
|
|||||||
if utils.CanLogDebug() {
|
if utils.CanLogDebug() {
|
||||||
log.Println("copying with readv")
|
log.Println("copying with readv")
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
buffers, err = ReadFromMultiReader(rawConn, mr)
|
buffers, err = ReadFromMultiReader(rawConn, mr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
num, err2 := buffers.WriteTo(writeConn)
|
var num int64
|
||||||
|
var err2 error
|
||||||
|
|
||||||
|
//如vless协议,肯定走这里,因为 vless.UserConn 实现了 utils.MultiWriter
|
||||||
|
if isWriteConn_a_MultiWriter {
|
||||||
|
num, err2 = multiWriter.WriteBuffers(buffers)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
num, err2 = buffers.WriteTo(writeConn)
|
||||||
|
}
|
||||||
|
|
||||||
allnum += num
|
allnum += num
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
err = err2
|
err = err2
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseNetBuffers(buffers)
|
ReleaseNetBuffers(buffers)
|
||||||
}
|
}
|
||||||
classic:
|
classic:
|
||||||
|
@@ -113,7 +113,7 @@ type ProxyCommon interface {
|
|||||||
|
|
||||||
//use dc.Host, dc.Insecure, dc.Utls
|
//use dc.Host, dc.Insecure, dc.Utls
|
||||||
func prepareTLS_forClient(com ProxyCommon, dc *DialConf) error {
|
func prepareTLS_forClient(com ProxyCommon, dc *DialConf) error {
|
||||||
com.setTLS_Client(tlsLayer.NewTlsClient(dc.Host, dc.Insecure, dc.Utls))
|
com.setTLS_Client(tlsLayer.NewClient(dc.Host, dc.Insecure, dc.Utls))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ func prepareTLS_forProxyCommon_withURL(u *url.URL, isclient bool, com ProxyCommo
|
|||||||
if isclient {
|
if isclient {
|
||||||
utlsStr := u.Query().Get("utls")
|
utlsStr := u.Query().Get("utls")
|
||||||
useUtls := utlsStr != "" && utlsStr != "false" && utlsStr != "0"
|
useUtls := utlsStr != "" && utlsStr != "false" && utlsStr != "0"
|
||||||
com.setTLS_Client(tlsLayer.NewTlsClient(u.Host, insecure, useUtls))
|
com.setTLS_Client(tlsLayer.NewClient(u.Host, insecure, useUtls))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
certFile := u.Query().Get("cert")
|
certFile := u.Query().Get("cert")
|
||||||
|
@@ -172,10 +172,11 @@ func (c *Client) Handshake(underlay net.Conn, target *netLayer.Addr) (io.ReadWri
|
|||||||
utils.PutBuf(buf)
|
utils.PutBuf(buf)
|
||||||
|
|
||||||
return &UserConn{
|
return &UserConn{
|
||||||
Conn: underlay,
|
Conn: underlay,
|
||||||
uuid: *c.user,
|
uuid: *c.user,
|
||||||
version: c.version,
|
version: c.version,
|
||||||
isUDP: target.Network == "udp",
|
isUDP: target.Network == "udp",
|
||||||
|
underlayIsBasic: netLayer.IsBasicConn(underlay),
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -390,6 +390,7 @@ realPart:
|
|||||||
uuid: thisUUIDBytes,
|
uuid: thisUUIDBytes,
|
||||||
version: int(version),
|
version: int(version),
|
||||||
isUDP: addr.Network == "udp",
|
isUDP: addr.Network == "udp",
|
||||||
|
underlayIsBasic: netLayer.IsBasicConn(underlay),
|
||||||
isServerEnd: true,
|
isServerEnd: true,
|
||||||
}, addr, nil
|
}, addr, nil
|
||||||
|
|
||||||
|
@@ -30,12 +30,15 @@ const (
|
|||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//实现 net.Conn 以及 utils.MultiWriter
|
||||||
type UserConn struct {
|
type UserConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
optionalReader io.Reader //在使用了缓存读取握手包头后,就产生了buffer中有剩余数据的可能性,此时就要使用MultiReader
|
optionalReader io.Reader //在使用了缓存读取握手包头后,就产生了buffer中有剩余数据的可能性,此时就要使用MultiReader
|
||||||
|
|
||||||
remainFirstBufLen int //记录读取握手包头时读到的buf的长度. 如果我们读超过了这个部分的话,实际上我们就可以不再使用 optionalReader 读取, 而是直接从Conn读取
|
remainFirstBufLen int //记录读取握手包头时读到的buf的长度. 如果我们读超过了这个部分的话,实际上我们就可以不再使用 optionalReader 读取, 而是直接从Conn读取
|
||||||
|
|
||||||
|
underlayIsBasic bool
|
||||||
|
|
||||||
uuid [16]byte
|
uuid [16]byte
|
||||||
convertedUUIDStr string
|
convertedUUIDStr string
|
||||||
version int
|
version int
|
||||||
@@ -62,6 +65,36 @@ func (uc *UserConn) GetIdentityStr() string {
|
|||||||
return uc.convertedUUIDStr
|
return uc.convertedUUIDStr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *UserConn) canDirectWrite() bool {
|
||||||
|
return c.version == 1 && !c.isUDP || c.version == 0 && !(c.isServerEnd && !c.isntFirstPacket)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UserConn) WriteBuffers(buffers [][]byte) (int64, error) {
|
||||||
|
|
||||||
|
if c.canDirectWrite() {
|
||||||
|
|
||||||
|
//底层连接可以是 ws,或者 tls,或者 基本连接
|
||||||
|
|
||||||
|
//本作的 ws.Conn 实现了 utils.MultiWriter
|
||||||
|
|
||||||
|
if c.underlayIsBasic {
|
||||||
|
nb := net.Buffers(buffers)
|
||||||
|
return nb.WriteTo(c.Conn)
|
||||||
|
|
||||||
|
} else if mr, ok := c.Conn.(utils.MultiWriter); ok {
|
||||||
|
return mr.WriteBuffers(buffers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bigbs, dup := utils.MergeBuffers(buffers)
|
||||||
|
n, e := c.Write(bigbs)
|
||||||
|
if dup {
|
||||||
|
utils.PutPacket(bigbs)
|
||||||
|
}
|
||||||
|
return int64(n), e
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//如果是udp,则是多线程不安全的,如果是tcp,则安不安全看底层的链接。
|
//如果是udp,则是多线程不安全的,如果是tcp,则安不安全看底层的链接。
|
||||||
// 这里规定,如果是UDP,则 每Write一遍,都要Write一个 完整的UDP 数据包
|
// 这里规定,如果是UDP,则 每Write一遍,都要Write一个 完整的UDP 数据包
|
||||||
func (uc *UserConn) Write(p []byte) (int, error) {
|
func (uc *UserConn) Write(p []byte) (int, error) {
|
||||||
|
@@ -10,22 +10,25 @@ import (
|
|||||||
utls "github.com/refraction-networking/utls"
|
utls "github.com/refraction-networking/utls"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 关于utls的简单分析,可参考
|
||||||
|
//https://github.com/hahahrfool/v2ray_simple/discussions/7
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
tlsConfig *tls.Config
|
tlsConfig *tls.Config
|
||||||
useTls bool
|
use_uTls bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTlsClient(host string, insecure bool, useTls bool) *Client {
|
func NewClient(host string, insecure bool, use_uTls bool) *Client {
|
||||||
|
|
||||||
c := &Client{
|
c := &Client{
|
||||||
tlsConfig: &tls.Config{
|
tlsConfig: &tls.Config{
|
||||||
InsecureSkipVerify: insecure,
|
InsecureSkipVerify: insecure,
|
||||||
ServerName: host,
|
ServerName: host,
|
||||||
},
|
},
|
||||||
useTls: useTls,
|
use_uTls: use_uTls,
|
||||||
}
|
}
|
||||||
|
|
||||||
if useTls && utils.CanLogInfo() {
|
if use_uTls && utils.CanLogInfo() {
|
||||||
log.Println("using utls and Chrome fingerprint for", host)
|
log.Println("using utls and Chrome fingerprint for", host)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +37,7 @@ func NewTlsClient(host string, insecure bool, useTls bool) *Client {
|
|||||||
|
|
||||||
func (c *Client) Handshake(underlay net.Conn) (tlsConn *Conn, err error) {
|
func (c *Client) Handshake(underlay net.Conn) (tlsConn *Conn, err error) {
|
||||||
|
|
||||||
if c.useTls {
|
if c.use_uTls {
|
||||||
utlsConn := utls.UClient(underlay, &utls.Config{
|
utlsConn := utls.UClient(underlay, &utls.Config{
|
||||||
InsecureSkipVerify: c.tlsConfig.InsecureSkipVerify,
|
InsecureSkipVerify: c.tlsConfig.InsecureSkipVerify,
|
||||||
ServerName: c.tlsConfig.ServerName,
|
ServerName: c.tlsConfig.ServerName,
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// Package utils provides utils that needed by all sub-packages in verysimle
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "flag"
|
import "flag"
|
||||||
|
94
utils/multi.go
Normal file
94
utils/multi.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
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
|
||||||
|
}
|
@@ -67,17 +67,17 @@ func PutPacket(bs []byte) {
|
|||||||
c := cap(bs)
|
c := cap(bs)
|
||||||
if c < MaxBufLen {
|
if c < MaxBufLen {
|
||||||
if c >= StandardBytesLength {
|
if c >= StandardBytesLength {
|
||||||
standardBytesPool.Put(bs[:c])
|
standardBytesPool.Put(bs[:StandardBytesLength])
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
standardPacketPool.Put(bs[:c])
|
standardPacketPool.Put(bs[:MaxBufLen])
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从Pool中获取一个 StandardBytesLength 长度的 []byte
|
// 从Pool中获取一个 StandardBytesLength 长度的 []byte
|
||||||
func GetMTU() []byte {
|
func GetMTU() []byte {
|
||||||
return standardBytesPool.Get().([]byte)[:StandardBytesLength]
|
return standardBytesPool.Get().([]byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从pool中获取 []byte, 根据给出长度不同,来源于的Pool会不同.
|
// 从pool中获取 []byte, 根据给出长度不同,来源于的Pool会不同.
|
||||||
@@ -98,8 +98,8 @@ func PutBytes(bs []byte) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
} else if c >= StandardBytesLength && c < MaxBufLen {
|
} else if c >= StandardBytesLength && c < MaxBufLen {
|
||||||
standardBytesPool.Put(bs[:c])
|
standardBytesPool.Put(bs[:StandardBytesLength])
|
||||||
} else if c >= MaxBufLen {
|
} else if c >= MaxBufLen {
|
||||||
standardPacketPool.Put(bs[:c])
|
standardPacketPool.Put(bs[:MaxBufLen])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
// Package utils provides utils that needed by all sub-packages in verysimle
|
|
||||||
package utils
|
|
||||||
|
|
||||||
//具体实现见 readv_*.go; 用 GetReadVReader() 函数来获取本平台的对应实现。
|
|
||||||
type MultiReader interface {
|
|
||||||
Init([][]byte)
|
|
||||||
Read(fd uintptr) int32
|
|
||||||
Clear()
|
|
||||||
}
|
|
18
ws/client.go
18
ws/client.go
@@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gobwas/ws"
|
"github.com/gobwas/ws"
|
||||||
"github.com/gobwas/ws/wsutil"
|
"github.com/gobwas/ws/wsutil"
|
||||||
|
"github.com/hahahrfool/v2ray_simple/netLayer"
|
||||||
"github.com/hahahrfool/v2ray_simple/utils"
|
"github.com/hahahrfool/v2ray_simple/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,10 +45,7 @@ func (c *Client) Handshake(underlay net.Conn) (net.Conn, error) {
|
|||||||
// 但是仔细思考,发现tls握手是在websocket的外部发生的,而我们传输的是数据的内层tls握手,那么就和Dialer没关系了,dialer只是负责读最初的握手部分;
|
// 但是仔细思考,发现tls握手是在websocket的外部发生的,而我们传输的是数据的内层tls握手,那么就和Dialer没关系了,dialer只是负责读最初的握手部分;
|
||||||
// 所以我们就算要配置buffer尺寸,也不是在这里配置,而是要配置 theConn.w 的buffer
|
// 所以我们就算要配置buffer尺寸,也不是在这里配置,而是要配置 theConn.w 的buffer
|
||||||
|
|
||||||
//const bufsize = 1024 * 10
|
|
||||||
d := ws.Dialer{
|
d := ws.Dialer{
|
||||||
//ReadBufferSize: bufsize,
|
|
||||||
//WriteBufferSize: bufsize,
|
|
||||||
NetDial: func(ctx context.Context, net, addr string) (net.Conn, error) {
|
NetDial: func(ctx context.Context, net, addr string) (net.Conn, error) {
|
||||||
return underlay, nil
|
return underlay, nil
|
||||||
},
|
},
|
||||||
@@ -64,11 +62,12 @@ func (c *Client) Handshake(underlay net.Conn) (net.Conn, error) {
|
|||||||
// 所以我们的用例中,br一定是nil
|
// 所以我们的用例中,br一定是nil
|
||||||
|
|
||||||
theConn := &Conn{
|
theConn := &Conn{
|
||||||
Conn: underlay,
|
Conn: underlay,
|
||||||
state: ws.StateClientSide,
|
state: ws.StateClientSide,
|
||||||
|
underlayIsBasic: netLayer.IsBasicConn(underlay),
|
||||||
//w: wsutil.NewWriter(underlay, ws.StateClientSide, ws.OpBinary),
|
//w: wsutil.NewWriter(underlay, ws.StateClientSide, ws.OpBinary),
|
||||||
}
|
}
|
||||||
//theConn.w.DisableFlush() //发现使用ws分片功能的话会出问题,所以就先关了. 搞清楚分片的问题再说。
|
//theConn.w.DisableFlush() //使用ws分片功能会降低性能
|
||||||
|
|
||||||
// 根据 gobwas/ws的代码,在服务器没有返回任何数据时,br为nil
|
// 根据 gobwas/ws的代码,在服务器没有返回任何数据时,br为nil
|
||||||
if br == nil {
|
if br == nil {
|
||||||
@@ -153,11 +152,12 @@ func (edc *EarlyDataConn) Write(p []byte) (int, error) {
|
|||||||
utils.PutBuf(outBuf)
|
utils.PutBuf(outBuf)
|
||||||
|
|
||||||
theConn := &Conn{
|
theConn := &Conn{
|
||||||
Conn: edc.Conn,
|
Conn: edc.Conn,
|
||||||
state: ws.StateClientSide,
|
state: ws.StateClientSide,
|
||||||
|
underlayIsBasic: netLayer.IsBasicConn(edc.Conn),
|
||||||
}
|
}
|
||||||
|
|
||||||
//实测总是 br==nil,就算发送了earlydata也是如此
|
//实测总是 br==nil,就算发送了earlydata也是如此;不过理论上有可能粘包,只要远程目标服务器的响应够快
|
||||||
|
|
||||||
if br == nil {
|
if br == nil {
|
||||||
//log.Println(" br == nil")
|
//log.Println(" br == nil")
|
||||||
|
61
ws/conn.go
61
ws/conn.go
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/hahahrfool/v2ray_simple/utils"
|
"github.com/hahahrfool/v2ray_simple/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 实现 net.Conn 以及 utils.MultiWriter
|
||||||
// 因为 gobwas/ws 不包装conn,在写入和读取二进制时需要使用 较为底层的函数才行,并未被提供标准的Read和Write
|
// 因为 gobwas/ws 不包装conn,在写入和读取二进制时需要使用 较为底层的函数才行,并未被提供标准的Read和Write
|
||||||
// 因此我们包装一下,统一使用Read和Write函数 来读写 二进制数据。因为我们这里是代理,
|
// 因此我们包装一下,统一使用Read和Write函数 来读写 二进制数据。因为我们这里是代理,
|
||||||
// 所以我们默认 抛弃 websocket的 数据帧 长度。
|
// 所以我们默认 抛弃 websocket的 数据帧 长度。
|
||||||
@@ -24,6 +25,8 @@ type Conn struct {
|
|||||||
remainLenForLastFrame int64
|
remainLenForLastFrame int64
|
||||||
|
|
||||||
serverEndGotEarlyData []byte
|
serverEndGotEarlyData []byte
|
||||||
|
|
||||||
|
underlayIsBasic bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read websocket binary frames
|
//Read websocket binary frames
|
||||||
@@ -114,6 +117,60 @@ func (c *Conn) Read(p []byte) (int, error) {
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//实现 utils.MultiWriter
|
||||||
|
// 主要是针对一串数据的情况,如果底层连接可以用writev, 此时我们不要每一小段都包包头 然后写N次,
|
||||||
|
// 而是只在最前面包数据头,然后即可用writev 一次发送出去
|
||||||
|
// 比如从 socks5 读数据,写入 tcp +ws + vless 协议, 就是这种情况
|
||||||
|
// 若底层是tls,那我们也合并再发出,这样能少些很多头部,也能减少Write次数
|
||||||
|
func (c *Conn) WriteBuffers(buffers [][]byte) (int64, error) {
|
||||||
|
|
||||||
|
nb := net.Buffers(buffers)
|
||||||
|
if c.underlayIsBasic {
|
||||||
|
allLen := utils.BuffersLen(buffers)
|
||||||
|
|
||||||
|
if c.state == ws.StateClientSide {
|
||||||
|
|
||||||
|
//如果是客户端,需要将全部数据进行掩码处理,超烦人的!
|
||||||
|
//我们直接将所有数据合并到一起, 然后自行写入 frame, 而不是使用 wsutil的函数,能省内存拷贝开销
|
||||||
|
|
||||||
|
bigbs, dup := utils.MergeBuffers(buffers)
|
||||||
|
frame := ws.NewFrame(ws.OpBinary, true, bigbs)
|
||||||
|
frame = ws.MaskFrameInPlace(frame)
|
||||||
|
e := ws.WriteFrame(c.Conn, frame)
|
||||||
|
if dup {
|
||||||
|
utils.PutPacket(bigbs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e != nil {
|
||||||
|
return 0, e
|
||||||
|
}
|
||||||
|
return int64(allLen), nil
|
||||||
|
} else {
|
||||||
|
wsH := ws.Header{
|
||||||
|
Fin: true,
|
||||||
|
OpCode: ws.OpBinary,
|
||||||
|
Length: int64(allLen),
|
||||||
|
}
|
||||||
|
|
||||||
|
e := ws.WriteHeader(c.Conn, wsH)
|
||||||
|
if e != nil {
|
||||||
|
return 0, e
|
||||||
|
}
|
||||||
|
return nb.WriteTo(c.Conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
bigbs, dup := utils.MergeBuffers(buffers)
|
||||||
|
n, e := c.Write(bigbs)
|
||||||
|
if dup {
|
||||||
|
utils.PutPacket(bigbs)
|
||||||
|
|
||||||
|
}
|
||||||
|
return int64(n), e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Write websocket binary frames
|
//Write websocket binary frames
|
||||||
func (c *Conn) Write(p []byte) (n int, e error) {
|
func (c *Conn) Write(p []byte) (n int, e error) {
|
||||||
//log.Println("ws Write called", len(p))
|
//log.Println("ws Write called", len(p))
|
||||||
@@ -122,7 +179,7 @@ func (c *Conn) Write(p []byte) (n int, e error) {
|
|||||||
// 不分片的效率更高,因为无需缓存,zero copy
|
// 不分片的效率更高,因为无需缓存,zero copy
|
||||||
|
|
||||||
if c.state == ws.StateClientSide {
|
if c.state == ws.StateClientSide {
|
||||||
e = wsutil.WriteClientBinary(c.Conn, p)
|
e = wsutil.WriteClientBinary(c.Conn, p) //实际我查看它的代码,发现Client端 最终调用到的 writeFrame 函数 还是多了一次拷贝; 它是为了防止篡改客户数据;但是我们代理的话不会使用数据,只是转发而已
|
||||||
} else {
|
} else {
|
||||||
e = wsutil.WriteServerBinary(c.Conn, p)
|
e = wsutil.WriteServerBinary(c.Conn, p)
|
||||||
}
|
}
|
||||||
@@ -159,8 +216,6 @@ func (c *Conn) Write(p []byte) (n int, e error) {
|
|||||||
|
|
||||||
// 在调用了 DisableFlush 方法后,还是必须要调用 Flush, 否则还是什么也不写入
|
// 在调用了 DisableFlush 方法后,还是必须要调用 Flush, 否则还是什么也不写入
|
||||||
e = c.w.Flush()
|
e = c.w.Flush()
|
||||||
|
|
||||||
//似乎Flush之后还要Reset?不知道是不是没Reset 导致了 分片时 读取出问题的情况
|
|
||||||
}
|
}
|
||||||
//log.Println("ws Write finish", n, e)
|
//log.Println("ws Write finish", n, e)
|
||||||
return
|
return
|
||||||
|
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gobwas/ws"
|
"github.com/gobwas/ws"
|
||||||
"github.com/gobwas/ws/wsutil"
|
"github.com/gobwas/ws/wsutil"
|
||||||
|
"github.com/hahahrfool/v2ray_simple/netLayer"
|
||||||
"github.com/hahahrfool/v2ray_simple/utils"
|
"github.com/hahahrfool/v2ray_simple/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -105,8 +106,9 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) {
|
|||||||
//log.Println("thePotentialEarlyData", len(thePotentialEarlyData))
|
//log.Println("thePotentialEarlyData", len(thePotentialEarlyData))
|
||||||
|
|
||||||
theConn := &Conn{
|
theConn := &Conn{
|
||||||
Conn: underlay,
|
Conn: underlay,
|
||||||
state: ws.StateServerSide,
|
underlayIsBasic: netLayer.IsBasicConn(underlay),
|
||||||
|
state: ws.StateServerSide,
|
||||||
//w: wsutil.NewWriter(underlay, ws.StateServerSide, ws.OpBinary),
|
//w: wsutil.NewWriter(underlay, ws.StateServerSide, ws.OpBinary),
|
||||||
r: wsutil.NewServerSideReader(underlay),
|
r: wsutil.NewServerSideReader(underlay),
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user