IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> go实现TCP协议下的端口映射透传功能 -> 正文阅读

[网络协议]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操作。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 17:02:36  更:2021-08-23 17:04:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:30:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码