LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

【C#】利用现有的Windows远程桌面功能,通过P2P连接直接访问对方的远程桌面服务

admin
2025年6月23日 17:26 本文热度 42

解决方案设计

架构概述


关键组件

  • 协调服务器:交换客户端端点信息

  • P2P客户端:建立直接连接并设置端口转发

  • Windows远程桌面:使用标准RDP协议

完整代码实现

1. 协调服务器 (P2PCoordinator.cs)

using System;

using System.Collections.Generic;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.Threading;


class P2PCoordinator

{

    private const int ServerPort = 11000;

    private TcpListener _tcpListener;

    

    private readonly Dictionary<string, IPEndPoint> _tcpEndpoints = new();

    private readonly Dictionary<string, TcpClient> _tcpConnections = new();

    

    private readonly object _lock = new object();

    private bool _isRunning = true;


    public P2PCoordinator()

    {

        try

        {

            _tcpListener = new TcpListener(IPAddress.Any, ServerPort);

            Console.WriteLine($"P2P协调服务器启动,监听端口: {ServerPort}");

        }

        catch (Exception ex)

        {

            Console.WriteLine($"服务器初始化失败: {ex.Message}");

            Environment.Exit(1);

        }

    }


    public void Start()

    {

        new Thread(ListenTcp).Start();

        

        Console.WriteLine("服务器运行中. 按任意键停止...");

        Console.ReadKey();

        Stop();

    }


    private void ListenTcp()

    {

        try

        {

            _tcpListener.Start();

            Console.WriteLine("TCP监听已启动");

            

            while (_isRunning)

            {

                TcpClient client = _tcpListener.AcceptTcpClient();

                new Thread(() => HandleTcpClient(client)).Start();

            }

        }

        catch (Exception ex)

        {

            if (_isRunning) Console.WriteLine($"TCP监听错误: {ex.Message}");

        }

    }


    private void HandleTcpClient(TcpClient client)

    {

        string clientId = null;

        try

        {

            NetworkStream stream = client.GetStream();

            byte[] buffer = new byte[1024];

            int bytesRead = stream.Read(buffer, 0, buffer.Length);

            if (bytesRead == 0) return;


            string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);

            string[] parts = message.Split(':');

            if (parts.Length < 2) return;


            string command = parts[0];

            clientId = parts[1];

            var clientEP = (IPEndPoint)client.Client.RemoteEndPoint;


            Console.WriteLine($"[TCP] {clientId} 连接: {clientEP}");


            lock (_lock)

            {

                if (command == "REGISTER")

                {

                    _tcpEndpoints[clientId] = clientEP;

                    _tcpConnections[clientId] = client;

                    Console.WriteLine($"[注册] {clientId} -> {clientEP}");

                    

                    SendTcpResponse(client, "REGISTERED");

                }

                else if (command == "CONNECT" && parts.Length > 2)

                {

                    string targetId = parts[2];

                    Console.WriteLine($"[连接请求] {clientId} -> {targetId}");

                    HandleConnectionRequest(clientId, targetId);

                }

            }


            // 处理后续消息

            while (_isRunning)

            {

                bytesRead = stream.Read(buffer, 0, buffer.Length);

                if (bytesRead == 0) break;


                message = Encoding.ASCII.GetString(buffer, 0, bytesRead);

                parts = message.Split(':');

                command = parts[0];


                if (command == "HEARTBEAT")

                {

                    // 心跳检测

                    SendTcpResponse(client, "HEARTBEAT_ACK");

                }

            }

        }

        catch (Exception ex)

        {

            Console.WriteLine($"处理TCP客户端错误: {ex.Message}");

        }

        finally

        {

            if (clientId != null)

            {

                lock (_lock)

                {

                    _tcpConnections.Remove(clientId);

                    _tcpEndpoints.Remove(clientId);

                }

            }

            client.Close();

        }

    }


    private void HandleConnectionRequest(string fromClient, string toClient)

    {

        lock (_lock)

        {

            if (!_tcpConnections.ContainsKey(fromClient))

            {

                Console.WriteLine($"[错误] 源客户端未连接: {fromClient}");

                return;

            }

            

            if (!_tcpConnections.ContainsKey(toClient))

            {

                SendTcpResponse(_tcpConnections[fromClient], "ERROR:目标客户端未连接");

                Console.WriteLine($"[错误] 目标客户端未连接: {toClient}");

                return;

            }

            

            if (!_tcpEndpoints.TryGetValue(fromClient, out IPEndPoint fromEp) ||

                !_tcpEndpoints.TryGetValue(toClient, out IPEndPoint toEp))

            {

                SendTcpResponse(_tcpConnections[fromClient], "ERROR:端点信息不完整");

                Console.WriteLine($"[错误] 端点信息不完整: {fromClient} -> {toClient}");

                return;

            }


            // 交换端点信息

            string fromMessage = $"PEER_INFO:{toClient}:{toEp.Address}:{toEp.Port}";

            string toMessage = $"PEER_INFO:{fromClient}:{fromEp.Address}:{fromEp.Port}";

            

            SendTcpResponse(_tcpConnections[fromClient], fromMessage);

            SendTcpResponse(_tcpConnections[toClient], toMessage);

            

            Console.WriteLine($"[端点交换] {fromClient} <-> {toClient}");

            Console.WriteLine($"  {fromEp} <-> {toEp}");

        }

    }


    private void SendTcpResponse(TcpClient client, string message)

    {

        try

        {

            if (client.Connected)

            {

                NetworkStream stream = client.GetStream();

                byte[] data = Encoding.ASCII.GetBytes(message);

                stream.Write(data, 0, data.Length);

            }

        }

        catch (Exception ex)

        {

            Console.WriteLine($"发送TCP响应错误: {ex.Message}");

        }

    }


    private void Stop()

    {

        Console.WriteLine("停止服务器...");

        _isRunning = false;

        

        try

        {

            lock (_lock)

            {

                foreach (var client in _tcpConnections.Values)

                {

                    try { client.Close(); } catch { }

                }

                _tcpConnections.Clear();

                _tcpEndpoints.Clear();

            }

            

            _tcpListener.Stop();

            Console.WriteLine("服务器已停止");

        }

        catch (Exception ex)

        {

            Console.WriteLine($"停止服务器错误: {ex.Message}");

        }

    }


    static void Main(string[] args)

    {

        Console.Title = "P2P协调服务器";

        Console.WriteLine("=== P2P协调服务器 ===");

        Console.WriteLine("用于远程桌面直连");

        Console.WriteLine("端口: " + ServerPort);

        Console.WriteLine(new string('=', 50));

        

        var server = new P2PCoordinator();

        server.Start();

    }

}

2. P2P客户端 (P2PRdpClient.cs)

using System;

using System.Diagnostics;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.Threading;

using System.Runtime.InteropServices;


class P2PRdpClient

{

    // 配置参数

    private readonly string _serverIp;

    private readonly int _serverPort;

    private readonly string _clientId;

    

    // 网络组件

    private TcpClient _tcpServerConnection;

    private NetworkStream _tcpStream;

    

    // 状态变量

    private IPEndPoint _peerEp;

    private bool _isRunning = true;


    public P2PRdpClient(string serverIp, int serverPort, string clientId)

    {

        _serverIp = serverIp;

        _serverPort = serverPort;

        _clientId = clientId;

    }


    public void Start()

    {

        ConnectToServer();

        new Thread(Heartbeat).Start();


        Console.WriteLine("命令:");

        Console.WriteLine("  connect [目标ID] - 请求P2P连接");

        Console.WriteLine("  rdp [目标IP] [端口] - 启动远程桌面");

        Console.WriteLine("  exit - 退出程序");

        

        while (_isRunning)

        {

            Console.Write("> ");

            string input = Console.ReadLine();

            if (string.IsNullOrEmpty(input)) continue;

            

            string[] parts = input.Split(' ');

            string command = parts[0].ToLower();

            

            switch (command)

            {

                case "connect":

                    if (parts.Length > 1) RequestConnection(parts[1]);

                    else Console.WriteLine("缺少目标ID");

                    break;

                    

                case "rdp":

                    if (parts.Length > 2) StartRemoteDesktop(parts[1], int.Parse(parts[2]));

                    else Console.WriteLine("缺少IP或端口");

                    break;

                    

                case "exit":

                    _isRunning = false;

                    break;

                    

                default:

                    Console.WriteLine("未知命令");

                    break;

            }

        }

        

        // 清理资源

        _isRunning = false;

        _tcpServerConnection?.Close();

    }


    #region 服务器通信

    private void ConnectToServer()

    {

        try

        {

            _tcpServerConnection = new TcpClient(_serverIp, _serverPort);

            _tcpStream = _tcpServerConnection.GetStream();

            Console.WriteLine("已连接到协调服务器");


            string registerMsg = $"REGISTER:{_clientId}";

            byte[] data = Encoding.ASCII.GetBytes(registerMsg);

            _tcpStream.Write(data, 0, data.Length);


            new Thread(ReceiveFromServer).Start();

        }

        catch (Exception ex)

        {

            Console.WriteLine($"连接服务器失败: {ex.Message}");

        }

    }


    private void RequestConnection(string targetId)

    {

        string message = $"CONNECT:{_clientId}:{targetId}";

        byte[] data = Encoding.ASCII.GetBytes(message);

        _tcpStream.Write(data, 0, data.Length);

    }


    private void ReceiveFromServer()

    {

        try

        {

            byte[] buffer = new byte[1024];

            

            while (_isRunning)

            {

                int bytesRead = _tcpStream.Read(buffer, 0, buffer.Length);

                if (bytesRead == 0) break;


                string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);

                Console.WriteLine($"收到服务器消息: {message}");


                string[] parts = message.Split(':');

                if (parts[0] == "PEER_INFO")

                {

                    HandlePeerInfo(parts);

                }

                else if (parts[0] == "ERROR")

                {

                    Console.WriteLine($"服务器错误: {message.Substring(6)}");

                }

            }

        }

        catch (Exception ex)

        {

            Console.WriteLine($"接收服务器消息错误: {ex.Message}");

        }

    }


    private void HandlePeerInfo(string[] parts)

    {

        if (parts.Length < 4) return;

        

        string peerId = parts[1];

        string ip = parts[2];

        int port = int.Parse(parts[3]);

        

        _peerEp = new IPEndPoint(IPAddress.Parse(ip), port);

        

        Console.WriteLine($"目标端点: {_peerEp}");

        Console.WriteLine($"您可以使用以下命令启动远程桌面:");

        Console.WriteLine($"  rdp {ip} {port}");

    }

    #endregion


    #region 远程桌面功能

    private void StartRemoteDesktop(string ip, int port)

    {

        try

        {

            Console.WriteLine($"正在启动远程桌面连接: {ip}:{port}");

            

            // 使用mstsc.exe连接远程桌面

            ProcessStartInfo startInfo = new ProcessStartInfo

            {

                FileName = "mstsc.exe",

                Arguments = $"/v:{ip}:{port}",

                UseShellExecute = false

            };

            

            Process.Start(startInfo);

            Console.WriteLine("远程桌面已启动");

        }

        catch (Exception ex)

        {

            Console.WriteLine($"启动远程桌面失败: {ex.Message}");

        }

    }

    #endregion


    #region 辅助功能

    private void Heartbeat()

    {

        while (_isRunning)

        {

            try

            {

                Thread.Sleep(30000);

                if (_tcpServerConnection.Connected)

                {

                    byte[] data = Encoding.ASCII.GetBytes("HEARTBEAT");

                    _tcpStream.Write(data, 0, data.Length);

                }

            }

            catch (Exception ex)

            {

                Console.WriteLine($"发送心跳失败: {ex.Message}");

            }

        }

    }

    #endregion


    static void Main(string[] args)

    {

        if (args.Length < 2)

        {

            Console.WriteLine("用法: P2PRdpClient.exe [服务器IP] [客户端ID]");

            return;

        }

        

        string serverIp = args[0];

        string clientId = args[1];

        

        var client = new P2PRdpClient(serverIp, 11000, clientId);

        client.Start();

    }

}

使用流程

1. 部署协调服务器

P2PCoordinator.exe

2. 启动被控端客户端

P2PRdpClient.exe [服务器IP] ControlledPC

3. 启动控制端客户端

P2PRdpClient.exe [服务器IP] ControlPC

4. 建立P2P连接

在控制端输入:

connect ControlledPC

5. 启动远程桌面

在控制端输入:

rdp [被控端IP] [被控端端口]

技术实现细节

1. 端口转发方案(被控端)

要让远程桌面通过P2P连接工作,需要在被控端设置端口转发。以下是使用netsh设置端口转发的批处理脚本:

被控端设置端口转发 (setup_port_forward.bat):

@echo off

setlocal


REM 获取本机IP地址

for /f "tokens=14 delims= " %%i in ('ipconfig ^| findstr "IPv4"') do set local_ip=%%i


REM 设置端口转发 (需要管理员权限)

netsh interface portproxy add v4tov4 listenport=3389 listenaddress=%local_ip% connectport=3389 connectaddress=127.0.0.1


echo 端口转发已设置: %local_ip%:3389 -> 127.0.0.1:3389

echo 确保防火墙允许入站连接端口3389


pause

2. 防火墙配置(被控端)

允许远程桌面服务通过防火墙:

netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=TCP localport=3389 action=allow

3. 完整工作流程

  1. 被控端准备:

    • 启用Windows远程桌面服务

    • 运行端口转发脚本(管理员权限)

    • 启动客户端:P2PRdpClient.exe server_ip ControlledPC

  2. 控制端操作:

    • 启动客户端:P2PRdpClient.exe server_ip ControlPC

    • 输入:connect ControlledPC

    • 获取被控端公网IP和端口

    • 输入:rdp [被控端IP] [被控端端口]

  3. 网络穿透:

    • 控制端直接连接到被控端的3389端口

    • 被控端的端口转发将流量转到127.0.0.1:3389

    • 建立标准RDP连接

4. 连接示意图


增强功能

1. 自动端口检测脚本

port_checker.ps1 (PowerShell):

param(

    [string]$serverIp,

    [string]$clientId

)


# 启动客户端

Start-Process -FilePath "P2PRdpClient.exe" -ArgumentList $serverIp, $clientId


# 等待连接建立

Start-Sleep -Seconds 10


# 自动检测监听的端口

$ports = @(3389, 3390, 3391) # 常用RDP端口

$ipAddress = (Test-Connection -ComputerName $env:COMPUTERNAME -Count 1).IPV4Address.IPAddressToString


foreach ($port in $ports) {

    try {

        $listener = [System.Net.Sockets.TcpListener]$port

        $listener.Start()

        $listener.Stop()

        Write-Host "端口 $port 可用"

        

        # 设置端口转发

        netsh interface portproxy add v4tov4 listenport=$port listenaddress=$ipAddress connectport=3389 connectaddress=127.0.0.1

        

        # 添加防火墙规则

        netsh advfirewall firewall add rule name="RDP_P2P_$port" dir=in action=allow protocol=TCP localport=$port

        

        Write-Host "已设置端口转发: ${ipAddress}:${port} -> 127.0.0.1:3389"

        break

    }

    catch {

        Write-Host "端口 $port 已被占用"

    }

}

2. NAT穿透优化

对于复杂NAT环境,可使用以下增强穿透技术:

// 在客户端中添加

private void EnhanceNatPenetration(IPEndPoint peerEp)

{

    try

    {

        // UDP打洞增强

        using (var udpClient = new UdpClient(0))

        {

            for (int i = 0; i < 5; i++)

            {

                byte[] data = Encoding.ASCII.GetBytes($"PUNCH:{_clientId}:{i}");

                udpClient.Send(data, data.Length, peerEp);

                Thread.Sleep(200);

            }

        }

        

        // TCP连接尝试

        using (var tcpClient = new TcpClient())

        {

            tcpClient.Connect(peerEp);

            tcpClient.Close();

        }

    }

    catch

    {

        // 忽略错误,主要目的是打洞

    }

}

3. 连接测试工具

connection_tester.py:

import socket

import sys


def test_connection(ip, port):

    try:

        with socket.create_connection((ip, port), timeout=5) as sock:

            print(f"成功连接到 {ip}:{port}")

            return True

    except Exception as e:

        print(f"连接失败: {e}")

        return False


if __name__ == "__main__":

    if len(sys.argv) != 3:

        print("用法: connection_tester.py [IP] [端口]")

        sys.exit(1)

    

    test_connection(sys.argv[1], int(sys.argv[2]))

注意事项

  1. 防火墙配置:

    • 被控端需要开放RDP端口(默认3389)

    • 如果使用其他端口,需相应调整防火墙设置

  2. 网络要求:

    • 被控端需要允许入站RDP连接

    • 控制端需要出站访问协调服务器和P2P端口

  3. 安全建议:

    • 使用强密码保护远程桌面账户

    • 考虑使用VPN进行更安全的连接

    • 限制可连接IP地址范围

  4. 权限要求:

    • 端口转发脚本需要管理员权限

    • RDP服务需要启用

这个方案直接利用Windows内置的远程桌面功能,通过P2P连接实现直连,避免了在应用中重新实现远程桌面协议,既高效又可靠。


该文章在 2025/6/24 10:27:03 编辑过

全部评论1

admin
2025年6月24日 10:37
 相关教程:

C#实现混合P2P点对点直接连接方案(TCP + UDP),如果TCP连接失败则改用UDP连接[28]
  http://31815.oa22.cn

该评论在 2025/6/24 10:37:07 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved