golang实现简单的TCP代理

TCP Proxy

go 复制代码
package main

import (
	"io"
	"log"
	"net"
	"sync"
)

// go实现简单的TCP代理

// TCPProxy 是一个 TCP 代理
type TCPProxy struct {
	listenAddr string
	targetAddr string
}

// NewTCPProxy 创建一个新的 TCP 代理
func NewTCPProxy(listenAddr, targetAddr string) *TCPProxy {
	return &TCPProxy{
		listenAddr: listenAddr,
		targetAddr: targetAddr,
	}
}

// Serve 开始监听并代理 TCP 连接
func (p *TCPProxy) Serve() error {
	// 监听 TCP 连接
	listener, err := net.Listen("tcp", p.listenAddr)
	if err != nil {
		return err
	}
	defer listener.Close()
	log.Printf("tcp proxy listening at: %s\n", listener.Addr())
	// 处理 TCP 连接
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Printf("listener accept error: %s\n", err)
			continue
		}
		go p.handleConnection(conn)
	}
}

// handleConnection 处理 TCP 连接
func (p *TCPProxy) handleConnection(conn net.Conn) {
	defer conn.Close() // 关闭代理连接
	log.Printf("accepted new connection %s\n", conn.RemoteAddr())
	// 创建目标连接
	targetConn, err := net.Dial("tcp", p.targetAddr)
	if err != nil {
		log.Printf("dial target addr: %s error: %s\n", p.targetAddr, err)
		return
	}
	defer targetConn.Close() // 关闭目标连接
	log.Printf("tcp proxy client addr: %s\n", targetConn.LocalAddr())
	// 处理 TCP 流 ,在客户端和目标服务器之间双向转发数据
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		defer wg.Done()
		n, err := io.Copy(conn, targetConn)
		if err != nil {
			log.Printf("copy bytes from %s to %s error: %s", conn.RemoteAddr(), targetConn.RemoteAddr(), err)
			return
		}
		log.Printf("copied %d bytes from %s to %s", n, conn.RemoteAddr(), targetConn.RemoteAddr())

	}()
	go func() {
		defer wg.Done()
		n, err := io.Copy(targetConn, conn)
		if err != nil {
			log.Printf("copy bytes from %s to %s error: %s", targetConn.RemoteAddr(), conn.RemoteAddr(), err)
			return
		}
		log.Printf("copied %d bytes from %s to %s", n, targetConn.RemoteAddr(), conn.RemoteAddr())
	}()
	// 等待两个复制操作完成
	wg.Wait()
}

func main() {
	proxy := NewTCPProxy("127.0.0.1:8080", "127.0.0.1:8081")
	if err := proxy.Serve(); err != nil {
		log.Fatal(err)
	}
}

Server

go 复制代码
package main

import (
	"bufio"
	"log"
	"net"
)

// TCP Server端测试
// handle 处理函数
func handle(conn net.Conn) {
	defer conn.Close() // 关闭连接
	reader := bufio.NewReader(conn)
	for {
		var buf [512]byte
		n, err := reader.Read(buf[:]) // 读取数据
		if err != nil {
			log.Printf("read from client err: %s\n", err)
			break
		}
		log.Printf("read %d bytes from client\n", n)
		recvStr := string(buf[:n])
		log.Printf("received data from client: %s\n", recvStr)
		n, err = conn.Write([]byte(recvStr)) // 发送数据
		if err != nil {
			log.Printf("write data to client err: %s\n", err)
			return
		}
		log.Printf("write %d bytes to client\n", n)
	}
}

func main() {
	listener, err := net.Listen("tcp", "127.0.0.1:8081")
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("server listening at: %s\n", listener.Addr())
	for {
		conn, err := listener.Accept() // 监听客户端的连接请求
		if err != nil {
			log.Printf("listener accept error: %s\n", err)
			continue
		}
		go handle(conn) // 启动一个goroutine来处理客户端的连接请求
	}
}

Client

go 复制代码
package main

import (
	"bufio"
	"log"
	"net"
	"os"
	"strings"
)

// TCP 客户端
func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("client addr: %s\n", conn.LocalAddr())
	defer conn.Close() // 关闭TCP连接
	inputReader := bufio.NewReader(os.Stdin)
	for {
		input, _ := inputReader.ReadString('\n') // 读取用户输入
		inputInfo := strings.Trim(input, "\r\n")
		if strings.ToUpper(inputInfo) == "Q" { // 如果输入q就退出
			return
		}
		n, err := conn.Write([]byte(inputInfo)) // 发送数据
		if err != nil {
			log.Printf("write data to server err: %s\n", err)
			return
		}
		log.Printf("write %d bytes to server\n", n)
		buf := [512]byte{}
		n, err = conn.Read(buf[:])
		if err != nil {
			log.Printf("read data from server err: %s\n", err)
			return
		}
		log.Printf("read %d bytes from server\n", n)
		log.Printf("received data from server: %s\n", string(buf[:n]))
	}
}
相关推荐
techdashen23 分钟前
Go设计取舍之四: map不变时能否并发修改不同value
开发语言·后端·golang
深圳市爱派派智能科技有限公司38 分钟前
“高通 QCS8550 嵌入式主板 EC-A8550JD4:48 TOPS 算力上板“
网络·嵌入式·边缘计算·高通·qcs8550·天启智能·ec-a8550jd4
妍妍爱学习40 分钟前
技术破界 数智共生:华为星河AI网络商业峰会5月18日深圳启幕
网络·ai·生态·数智化·峰会
funnycoffee1231 小时前
Cisco ip access-list序号重排方法
linux·网络·tcp/ip
名字还没想好☜1 小时前
Go 表驱动测试实战:用 t.Run 子测试组织可维护的单元测试
golang·单元测试·log4j·go·testing
nvd112 小时前
GCP 4层 外部网络负载均衡器深度解析
运维·网络·负载均衡
乌萨奇也要立志学C++2 小时前
【Linux】传输层协议UDP与TCP详解
linux·tcp/ip·udp
golang学习记2 小时前
Claude Code写哪种变成语言最快?
golang·claude code
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题 第210题】【10_网络协议篇】第1题:说说 TCP/IP 网络五层模型
java·网络协议·tcp/ip·计算机网络·网络五层模型
ShuiShenHuoLe3 小时前
Go html/template 使用入门
开发语言·golang·html