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]))
	}
}
相关推荐
洁✘1 小时前
web基础与http协议
网络·网络协议·http
想睡好1 小时前
以太网的mac帧格式
网络·macos
曼诺尔雷迪亚兹2 小时前
Wireshark快速入门--对启动的后端程序进行抓包
网络·测试工具·wireshark
FreeBuf_3 小时前
新型“电力寄生虫“网络钓鱼攻击瞄准能源企业与知名品牌
网络·php·能源
类似不类似4 小时前
快速配置linux远程开发-go语言
开发语言·后端·golang
wang09075 小时前
网络协议之为什么要分层
网络·网络协议
ErizJ5 小时前
Golang|分布式索引架构
开发语言·分布式·后端·架构·golang
EasyDSS6 小时前
EasyCVR视频汇聚平台助力大型生产监控项目摄像机选型与应用
网络·人工智能·音视频
群联云防护小杜6 小时前
云服务器被黑客攻击应急响应与加固指南(上)
运维·服务器·人工智能·tcp/ip·自动化·压力测试
等猪的风7 小时前
openwrt作旁路由时的几个常见问题 openwrt作为旁路由配置zerotier 图文讲解
运维·服务器·网络