go语言实现TCP端口转发

有些时候项目会碰到需要端口转发的需求,比如:

  1. 一个服务发布在公共端口上,客户端进来的请求需要转发到另一个本地端口,或者另一台主机;或者
  2. 一个公共服务需要转到到多台内部服务上,轮询,按优先级等;或者
  3. 一个服务请求进来之前需要做请求检查,例如安全功能参数等检查,类似网关功能,只有验证通过的请求才能发送给实际服务器。
  4. 等等等

下面是一个实现TCP端口转发功能的代码例子。
这里例子将会起一个监听在端口fromport,然后把所有向此fromport发起的请求都转发到端口toport,当然必须先有另一个服务已经监听在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
        }
    }
}
    原文作者:CodingCode
    原文地址: https://www.jianshu.com/p/33844325268a
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞