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]))
	}
}
相关推荐
极客互动API几秒前
企业微信 iPad 协议服务搭建与 AI 回调实战
网络·汇编·人工智能·微信·企业微信·ipad
QH1392923188014 分钟前
Keysight N5183B N5183B 微波模拟信号发生器
网络·单片机·嵌入式硬件·集成测试·信息与通信
LabVIEW开发26 分钟前
基于原始套接字实现LabVIEW网络Ping检测的编程方法
网络·labview·labview知识·labview功能·labview程序
东莞和裕包装1 小时前
如何管控广州定制纸箱生产中的啤切精度与印刷色差质量问题
大数据·运维·网络·人工智能
Zguigo2 小时前
lesson19-23计算机网络数据链路层完全指南:从帧封装到滑动窗口协议
网络·计算机网络
abcefg_h3 小时前
MCP 实战指南:如何在项目中使用 Model Context Protocol 及其通信原理
开发语言·后端·golang·mcp
ylj_dev4 小时前
从 0 构建 AI Workload Platform(四):从单机工作流内核到可靠控制面
docker·postgresql·架构·golang
2401_894915534 小时前
Geo 优化源码部署实战:环境配置、参数调优完整指南
运维·服务器·数据库·tcp/ip·安全
肠畔码农4 小时前
Redis 主从复制内核深潜:从物理模型到全量增量同步的本质
网络·redis·php
FfHUCisI5 小时前
Golang database/sql 标准库基础
数据库·sql·golang