一个简单的tcp代理实现,对应用是透明的。
例如
某服务器对外留有一个公开访问端口,我们为了方便数据调试动态的将端口socket连接转发到其他服务中(Mysql,Redis等)。
这里以Mysql做个简单示例。
package main
import (
"fmt"
"log"
"net"
)
const (
// FromAddr 源端口
FromAddr = "127.0.0.1:3406"
// ToAddr 目的端口
ToAddr = "127.0.0.1:3306"
)
func main() {
// 启动监听
tcpListener()
}
// tcp监听
func tcpListener() {
listener, err := net.Listen("tcp", FromAddr)
if err != nil {
log.Fatalf("Listener.Accept.Error: %s %s\n", FromAddr, err.Error())
}
defer listener.Close()
for {
fConn, err := listener.Accept()
if err != nil {
fmt.Printf("f.Listener.Accept.Error: %s\n", err.Error())
} else {
fmt.Println("Listener.Accept.RemoteAddr:" + fConn.RemoteAddr().String())
}
go tcpProxy(fConn)
}
}
// tcp转发
func tcpProxy(fConn net.Conn) {
// 这边最好也做个协程,防止阻塞
tConn, err := net.Dial("tcp", ToAddr)
if err != nil {
fmt.Printf("t.Net.Dial.Error %s\n", ToAddr)
}
go connHandler(fConn, tConn)
go connHandler(tConn, fConn)
}
// 网络连接处理
func connHandler(r net.Conn, w net.Conn) {
defer r.Close()
defer w.Close()
var buffer = make([]byte, 100000)
for {
n, err := r.Read(buffer)
if err != nil {
break
}
n, err = w.Write(buffer[:n])
if err != nil {
break
}
}
}
运行测试:
Navicat连接:
此时终端也打印了对应日志: