124 lines
2.7 KiB
Go
124 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
"encoding/json"
|
|
)
|
|
|
|
type TcpListen struct {
|
|
Listen string `json:"listen"`
|
|
Backend string `json:"backend"`
|
|
}
|
|
|
|
type TcpListenConfig struct {
|
|
TcpListens []TcpListen `json:"tcpListens"`
|
|
}
|
|
|
|
// {
|
|
// "tcpListens": [
|
|
// "listen": ":8080",
|
|
// "backend": "11.22.33.44:8080"
|
|
// ]
|
|
// }
|
|
// https://blog.csdn.net/fyxichen/article/details/51505542
|
|
func main() {
|
|
|
|
tcpListenConfig, err := readConfigFile()
|
|
|
|
if err != nil {
|
|
fmt.Printf("Error in load config file: %v\n", err)
|
|
return
|
|
}
|
|
|
|
if len(tcpListenConfig.TcpListens) == 0 {
|
|
fmt.Println("Not find any mapping in config")
|
|
return
|
|
}
|
|
|
|
for _, tcpListen := range tcpListenConfig.TcpListens {
|
|
go server(tcpListen)
|
|
}
|
|
ExitChan := make(chan bool, 1)
|
|
<-ExitChan
|
|
}
|
|
|
|
func server(tcpListen TcpListen) {
|
|
lis, err := net.Listen("tcp", tcpListen.Listen)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
defer lis.Close()
|
|
fmt.Printf("Listen TCP at: %v --> %v\n", tcpListen.Listen, tcpListen.Backend)
|
|
for {
|
|
conn, err := lis.Accept()
|
|
if err != nil {
|
|
fmt.Printf("Listen error: %v\n", err)
|
|
continue
|
|
}
|
|
fmt.Printf("TCP connection from %v, local: %v\n", conn.RemoteAddr(), conn.LocalAddr())
|
|
go handle(tcpListen, conn)
|
|
}
|
|
}
|
|
|
|
func handle(tcpListen TcpListen, sconn net.Conn) {
|
|
defer sconn.Close()
|
|
ip := tcpListen.Backend
|
|
dconn, err := net.Dial("tcp", ip)
|
|
if err != nil {
|
|
fmt.Printf("Connect to %v failed:%v\n", ip, err)
|
|
return
|
|
}
|
|
ExitChan := make(chan bool, 1)
|
|
go func(sconn net.Conn, dconn net.Conn, Exit chan bool) {
|
|
_, err := io.Copy(dconn, sconn)
|
|
if err != nil {
|
|
errStr := fmt.Sprintf("%v", err)
|
|
if strings.Contains(errStr, "use of closed network connection") {
|
|
fmt.Printf("Connection closed: %v\n", ip)
|
|
} else {
|
|
fmt.Printf("Send data to %v failed:%v\n", ip, err)
|
|
}
|
|
}
|
|
ExitChan <- true
|
|
}(sconn, dconn, ExitChan)
|
|
go func(sconn net.Conn, dconn net.Conn, Exit chan bool) {
|
|
_, err := io.Copy(sconn, dconn)
|
|
if err != nil {
|
|
errStr := fmt.Sprintf("%v", err)
|
|
if strings.Contains(errStr, "use of closed network connection") {
|
|
fmt.Printf("Connection closed: %v\n", ip)
|
|
} else {
|
|
fmt.Printf("Receive data from %v failed:%v\n", ip, err)
|
|
}
|
|
}
|
|
ExitChan <- true
|
|
}(sconn, dconn, ExitChan)
|
|
<-ExitChan
|
|
dconn.Close()
|
|
}
|
|
|
|
func readConfigFile() (*TcpListenConfig, error) {
|
|
configFile, err := os.Open("tcp_listen_config.json")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer configFile.Close()
|
|
|
|
configFileBytes, err := ioutil.ReadAll(configFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var tcpListenConfig TcpListenConfig
|
|
err = json.Unmarshal(configFileBytes, &tcpListenConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &tcpListenConfig, nil
|
|
} |