go实现TCP协议下的端口映射透传功能

问题:

A、B、C三台计算机,A和B可以通讯,B和C可以通讯,但是A和C不能通讯(红色的虚线)。那如何让A和C通讯?

 

解决方案:

需要在B计算机,安装一个端口映射程序,其功能:A发送数据给B,B再把数据透传到C,C处理完后,把数据回应给B,B电脑透传给A。

代码实现:

package main

import (
	"fmt"
	"net"
	"os"
	"io"
)

func tcp_mapping_worker(r net.Conn, w net.Conn) {

	fmt.Printf("tcp_mapping_worker in\r\n")

	// #关闭socket
	defer r.Close()
	defer w.Close()

	fmt.Printf("Info: Mapping > (%s) -> (%s) > N bytes.\r\n", r.RemoteAddr(), w.RemoteAddr())

	_, err := io.Copy(w, r)

	if nil != err{
		fmt.Println("Info: Copy: ", err)
	}

	return
}

func tcp_mapping_request(local_conn net.Conn, remote_ip string, remotePort string) {

	// 目标IP和端口
	remoteAddress := fmt.Sprintf("%s:%s", remote_ip, remotePort)

	//
	remote_conn, err := net.Dial("tcp", remoteAddress)

	if nil != err {
		local_conn.Close()
		fmt.Printf("Error: Unable to connect to the remote server[%s:%s].\r\n", remote_ip, remotePort)
		return
	}

	//
	go tcp_mapping_worker(local_conn, remote_conn)
	go tcp_mapping_worker(remote_conn, local_conn)

}


func ServerSocket(remote_ip string, remote_port string, local_ip string, local_port string) {

	// 监听端口
	localAddress := fmt.Sprintf("%s:%s", local_ip, local_port)

	local_server, err := net.Listen("tcp", localAddress)

	if nil != err {
		fmt.Printf("开启socket [%s]失败\r\n", localAddress)
		return
	}

	defer local_server.Close()

	local_message := fmt.Sprintf("Event: Starting mapping service on %s:%s ...", local_ip, local_port)

	fmt.Println(local_message)

	for {
		
		localConn, err := local_server.Accept()

		if nil != err {
			//local_server.Close()
			fmt.Printf("Unable to accept a request, error: %s\n", err.Error())
            continue
		}

		
		go tcp_mapping_request(localConn, remote_ip, remote_port)

		fmt.Printf("Event: Receive mapping request from [%s]\r\n", localConn.RemoteAddr())

	}

}


func main() {


	remoteIP := “132.xxx.xxx.xxx”
	remotePort := “9090”


	localIP := “192.168.1.100”
	localPort := “8080”


	fmt.Println("remote_IP:", remoteIP)
	fmt.Println("remote_port:", remotePort)
	fmt.Println("local_IP:", localIP)
	fmt.Println("local_port:", localPort)

	ServerSocket(remoteIP, remotePort, localIP, localPort)

}


代码说明:

	local_server, err := net.Listen("tcp", localAddress)

	if nil != err {
		fmt.Printf("开启socket [%s]失败\r\n", localAddress)
		return
	}

B电脑的TCP服务监听。

	for {
		
		localConn, err := local_server.Accept()

		if nil != err {
			fmt.Printf("Unable to accept a request, error: %s\n", err.Error())
            continue
		}

		go tcp_mapping_request(localConn, remote_ip, remote_port)

		fmt.Printf("Event: Receive mapping request from [%s]\r\n", localConn.RemoteAddr())

	}

Accept等待A的客户端连接,一直阻塞,所以一直死循环等待连接。连接成功,启动一个协程tcp_mapping_request。

func tcp_mapping_request(local_conn net.Conn, remote_ip string, remotePort string) {

	// 目标IP和端口
	remoteAddress := fmt.Sprintf("%s:%s", remote_ip, remotePort)

	//
	remote_conn, err := net.Dial("tcp", remoteAddress)

	if nil != err {
		local_conn.Close()
		fmt.Printf("Error: Unable to connect to the remote server[%s:%s].\r\n", remote_ip, remotePort)
		return
	}

	//
	go tcp_mapping_worker(local_conn, remote_conn)
	go tcp_mapping_worker(remote_conn, local_conn)

}

协程tcp_mapping_request,Dial连接C服务前置,若连接成功,分别建立协程B->C和C->B的tcp_mapping_worker。

func tcp_mapping_worker(r net.Conn, w net.Conn) {

	fmt.Printf("tcp_mapping_worker in\r\n")

	// #关闭socket
	defer r.Close()
	defer w.Close()

	fmt.Printf("Info: Mapping > (%s) -> (%s) > N bytes.\r\n", r.RemoteAddr(), w.RemoteAddr())

	_, err := io.Copy(w, r)

	if nil != err{
		fmt.Println("Info: Copy: ", err)
	}

	return
}

协程tcp_mapping_worker,使用接口io.Copy,把r通道复制到w通道,这个是点睛之处,省掉TCP接口读read和write接口,直接使用copy接口,就完成了read和write操作。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值