有些時候項目會碰到需要端口轉(zhuǎn)發(fā)的需求,比如:
- 一個服務發(fā)布在公共端口上,客戶端進來的請求需要轉(zhuǎn)發(fā)到另一個本地端口斤寂,或者另一臺主機耿焊;或者
- 一個公共服務需要轉(zhuǎn)到到多臺內(nèi)部服務上,輪詢遍搞,按優(yōu)先級等罗侯;或者
- 一個服務請求進來之前需要做請求檢查,例如安全功能參數(shù)等檢查溪猿,類似網(wǎng)關功能钩杰,只有驗證通過的請求才能發(fā)送給實際服務器。
- 等等等
下面是一個實現(xiàn)TCP端口轉(zhuǎn)發(fā)功能的代碼例子诊县。
這里例子將會起一個監(jiān)聽在端口fromport讲弄,然后把所有向此fromport發(fā)起的請求都轉(zhuǎn)發(fā)到端口toport,當然必須先有另一個服務已經(jīng)監(jiān)聽在toport接受請求服務翎冲。
package main
import (
"os"
"fmt"
"net"
)
// Start a proxy server listen on fromport
// this proxy will then forward all request from fromport to toport
//
// Notice: a service must has been started on toport
func proxyStart(fromport, toport int) {
proxyaddr := fmt.Sprintf(":%d", fromport)
proxylistener, err := net.Listen("tcp", proxyaddr)
if err != nil {
fmt.Println("Unable to listen on: %s, error: %s\n", proxyaddr, err.Error())
os.Exit(1)
}
defer proxylistener.Close()
for {
proxyconn, err := proxylistener.Accept()
if err != nil {
fmt.Printf("Unable to accept a request, error: %s\n", err.Error())
continue
}
// Read a header firstly in case you could have opportunity to check request
// whether to decline or proceed the request
buffer := make([]byte, 1024)
n, err := proxyconn.Read(buffer)
if err != nil {
fmt.Printf("Unable to read from input, error: %s\n", err.Error())
continue
}
// TODO
// Your choice to make decision based on request header
targetaddr := fmt.Sprintf("localhost:%d", toport);
targetconn, err := net.Dial("tcp", targetaddr)
if err != nil {
fmt.Println("Unable to connect to: %s, error: %s\n", targetaddr, err.Error())
proxyconn.Close()
continue
}
n, err = targetconn.Write(buffer[:n])
if err != nil {
fmt.Printf("Unable to write to output, error: %s\n", err.Error())
proxyconn.Close()
targetconn.Close()
continue
}
go proxyRequest(proxyconn, targetconn)
go proxyRequest(targetconn, proxyconn)
}
}
// Forward all requests from r to w
func proxyRequest(r net.Conn, w net.Conn) {
defer r.Close()
defer w.Close()
var buffer = make([]byte, 4096000)
for {
n, err := r.Read(buffer)
if err != nil {
fmt.Printf("Unable to read from input, error: %s\n", err.Error())
break
}
n, err = w.Write(buffer[:n])
if err != nil {
fmt.Printf("Unable to write to output, error: %s\n", err.Error())
break
}
}
}