【go】我用Golang写了一个端口转发工具,但是性能极其低下,求各位帮忙分析分析
源码在这里:
https://github.com/cw1997/net...
package mainimport (
//"fmt"
"net"
//"os"
//"bufio"
"log"
"io/ioutil"
)
const (
ip = ""
port = 8899
)
func main() {
listen, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP(ip), port, ""})
if err != nil {
log.Println("监听端口失败:", err.Error())
return
}
log.Println("已初始化连接,等待客户端连接...")
Server(listen)
}
func Server(listen *net.TCPListener) {
for {
conn, err := listen.AcceptTCP()
if err != nil {
log.Println("接受客户端连接异常:", err.Error())
continue
}
log.Println("客户端连接来自:", conn.RemoteAddr().String())
defer conn.Close()
go func() {
data := make([]byte, 8192)
for {
i, err := conn.Read(data)
//log.Println("客户端发来数据:\n", string(data[0:i]))
// log.Println("客户端发来数据:\n", data)
log.Println("客户端发来数据:", i)
if err != nil {
log.Println("读取客户端数据错误:", err.Error())
break
}
go conn.Write(Send(data))
}
}()
}
}
func Send(data []byte) (buf []byte) {
pTCPConn, err := net.Dial("tcp", "127.0.0.1:80")
if err != nil {
//log.Fprintf(os.Stderr, "Error: %s", err.Error())
log.Printf("Error: %s", err.Error())
return
}
n, errWrite := pTCPConn.Write(data)
if errWrite != nil {
//log.Fprintf(os.Stderr, "Error: %s", errWrite.Error())
log.Printf("Error: %s", errWrite.Error())
return
}
defer pTCPConn.Close()
//log.Fprintf(os.Stdout, "writed: %d\n", n)
log.Printf("writed: %d\n", n)
buf, errRead := ioutil.ReadAll(pTCPConn)
//log.Println("服务端发来数据:\n", string(buf))
log.Println("服务端发来数据:", len(buf))
if errRead != nil {
//log.Fprintf(os.Stderr, "Error: %s", errRead.Error())
log.Printf("Error: %s", errRead.Error())
return
}
//r := len(buf)
//fmt.Fprintf(os.Stdout, string(buf[:r]))
//fmt.Fprintf(os.Stdout, "readed: %v\n", buf)
return
}
我用这个小工具代理一个开在内网的HTTP服务器,但是访问延时很大,一个很简单的phpinfo页面都要5s才能打开,其他页面资源比较多的网页那就更不用说了,卡的要命,求各位帮忙分析分析问题出在哪啊?(还有我是新手,很多内置库可能用法有误,还求各位轻喷并且帮忙指出来一下,谢谢各位老鸟帮忙)
另外我这个代码里面是写死了read buffer缓冲区为8192字节,如果遇到一个HTTP包尺寸很大该怎么处理呢?把这个[]byte的长度无限make大也不是办法啊
回答
mdzz
我就问一哈,
ReadAll是个啥?你为啥会想到这么用?
流和块的处理机制不一样啊。
转发就是流转发啊,readall是用在块上面的啊。
举个例子,readall基本你能看到的地方时,http请求结束之后,进行一次readall。他并不适合处理流量。
我建议用标准的方法。
这是一个转发到docker的proxy示例代码:
https://github.com/UESTC-BBS/...
核心代码是:
func forward(uconn net.Conn) { tconn, err := net.Dial("tcp", ADDRESS)
var wg sync.WaitGroup
go func(uconn net.Conn, tconn net.Conn) {
wg.Add(1)
defer wg.Done()
io.Copy(uconn, tconn)
uconn.Close()
}(uconn, tconn)
go func(uconn net.Conn, tconn net.Conn) {
wg.Add(1)
defer wg.Done()
io.Copy(tconn, uconn)
tconn.Close()
}(uconn, tconn)
wg.Wait()
}
还有点话要说,等下班了再写
叨逼几句:
Go语言中,
流量转发,一定是对readwriter1进行读取,写入到readwriter2,同时对readwriter2读取,写入到readwriter1,即:io.Copy。
流量拷贝,一定是使用multiwriter。
read,readall等操作,一般用于需要对流进行拆包的地方进行块处理,例如各种tcp(im、游戏)框架。
当然有特例,例如:单端口兼容多服务,https://github.com/jamescun/s...。
他肯定必须用了io.Copy,但是他肯定还用了块操作,不然没办法判断协议。
看了一下,Send函数在每次调用的时候都发生了dial,这可能是导致性能底下的原因之一.
大致写了下思路,没有错误处理和完善.
conn, err := linstener.Accept()go func(conn net.Conn){
rConn, err := net.Dial("tcp", "ip:port")
go func(){io.Copy(conn, rConn)}()
io.Copy(rConn, conn)
}(conn)
以上是 【go】我用Golang写了一个端口转发工具,但是性能极其低下,求各位帮忙分析分析 的全部内容, 来源链接: utcz.com/a/106776.html