因为IPV4的地址很紧张。但很多时候确定有要访问内网的需求。所以frp就是以内网穿透而出名。虽然现在多了很多关于异地组网的项目和产品,但frp依然没有被替代。现在让GPT 生成一个c# 版的,亲测包可直接食用。

使用场景:你的公网机器VPS 为A,跑服务端代码。被访问的机器B跑客户端代码。 C为任意一台客户端使用mstsc 访问A的8848端口,实现访问B的3389远程桌面。
  1. 服务端代码:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace ProxyServerApp
{
    public class ReverseProxyServer
    {
        private readonly int _listenPort;
        private TcpClient _connectedClient;
        private TcpListener _listener;

        public ReverseProxyServer(int listenPort)
        {
            _listenPort = listenPort;
        }

        public async Task StartAsync()
        {
            // 使用同一个TcpListener实例来监听客户端和C机器的连接
            _listener = new TcpListener(IPAddress.Any, _listenPort);
            _listener.Start();
            Console.WriteLine($"Server listening on port {_listenPort}.");

            // 开启监听客户端连接的任务
            _ = AcceptClientConnectionAsync();

            while (true)
            {
                // 接收来自 C 机器的连接
                var clientSocket = await _listener.AcceptSocketAsync();
                Console.WriteLine("Accepted connection from C.");

                if (_connectedClient == null)
                {
                    Console.WriteLine("No client connected from B.");
                    clientSocket.Close();
                    continue;
                }

                // 通过连接的 B 客户端转发流量
                var clientStream = _connectedClient.GetStream();
                var serverStream = new NetworkStream(clientSocket);

                await Task.WhenAny(
                    TransferDataAsync(serverStream, clientStream),
                    TransferDataAsync(clientStream, serverStream)
                );
            }
        }

        private async Task AcceptClientConnectionAsync()
        {
            while (true)
            {
                // 等待 B 客户端连接
                _connectedClient = await _listener.AcceptTcpClientAsync();
                Console.WriteLine("Client from B connected.");
            }
        }

        private async Task TransferDataAsync(NetworkStream source, NetworkStream destination)
        {
            var buffer = new byte[8192];
            try
            {
                int bytesRead;
                while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length)) > 0)
                {
                    await destination.WriteAsync(buffer, 0, bytesRead);
                }
            }
            catch (IOException ex) when (ex.InnerException is SocketException socketEx && 
                                        socketEx.SocketErrorCode == SocketError.ConnectionReset)
            {
                Console.WriteLine("Connection reset by peer.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Data transfer error: {ex.Message}");
            }
            finally
            {
                source.Close();
                destination.Close();
            }
        }

    }

    public class Program
    {
        public static async Task Main(string[] args)
        {
            int listenPort = 8848; // A 机器上的监听端口
            var server = new ReverseProxyServer(listenPort);
            await server.StartAsync();
        }
    }
}

  1. 客户端代码:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace ProxyClientApp
{
    public class PersistentClient
    {
        private readonly string _serverIp;
        private readonly int _serverPort;
        private readonly int _localPort;

        public PersistentClient(string serverIp, int serverPort, int localPort)
        {
            _serverIp = serverIp;
            _serverPort = serverPort;
            _localPort = localPort;
        }

        public async Task StartAsync()
        {
            while (true)
            {
                try
                {
                    using (var clientSocket = new TcpClient())
                    {
                        Console.WriteLine("Connecting to server...");
                        await clientSocket.ConnectAsync(_serverIp, _serverPort);

                        Console.WriteLine("Connected to server. Tunneling traffic...");
                        var serverStream = clientSocket.GetStream();

                        // 打开本地端口的远程桌面服务连接
                        using (var localSocket = new TcpClient("127.0.0.1", _localPort))
                        {
                            var localStream = localSocket.GetStream();

                            // 双向数据传输
                            await Task.WhenAny(
                                TransferDataAsync(serverStream, localStream),
                                TransferDataAsync(localStream, serverStream)
                            );
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Connection error: {ex.Message}. Retrying...");
                    await Task.Delay(5000); // 连接失败时的重试延迟
                }
            }
        }

        private async Task TransferDataAsync(NetworkStream source, NetworkStream destination)
        {
            var buffer = new byte[8192];
            try
            {
                int bytesRead;
                while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length)) > 0)
                {
                    await destination.WriteAsync(buffer, 0, bytesRead);
                }
            }
            catch (IOException ex) when (ex.InnerException is SocketException socketEx &&
                                         socketEx.SocketErrorCode == SocketError.ConnectionReset)
            {
                Console.WriteLine("Connection reset by peer.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Data transfer error: {ex.Message}");
            }
            finally
            {
                source.Close();
                destination.Close();
            }
        }

    }

    public class Program
    {
        public static async Task Main(string[] args)
        {
            string serverIp = "VPS公网IP"; // A 机器 IP
            int serverPort = 8848;             // A 机器上的监听端口
            int localPort = 3389;              // B 机器上远程桌面的端口

            var client = new PersistentClient(serverIp, serverPort, localPort);
            await client.StartAsync();
        }
    }
}

运行日志

客户端
image-1731169526293
服务端
image-1731169353256