LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

【C#】利用現(xiàn)有的Windows遠程桌面功能,通過P2P連接直接訪問對方的遠程桌面服務

admin
2025年6月23日 17:26 本文熱度 185

解決方案設計

架構(gòu)概述


關(guān)鍵組件

  • 協(xié)調(diào)服務器:交換客戶端端點信息

  • P2P客戶端:建立直接連接并設置端口轉(zhuǎn)發(fā)

  • Windows遠程桌面:使用標準RDP協(xié)議

完整代碼實現(xiàn)

1. 協(xié)調(diào)服務器 (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協(xié)調(diào)服務器啟動,監(jiān)聽端口: {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監(jiān)聽已啟動");

            

            while (_isRunning)

            {

                TcpClient client = _tcpListener.AcceptTcpClient();

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

            }

        }

        catch (Exception ex)

        {

            if (_isRunning) Console.WriteLine($"TCP監(jiān)聽錯誤: {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);

                }

            }


            // 處理后續(xù)消息

            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($"發(fā)送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協(xié)調(diào)服務器";

        Console.WriteLine("=== P2P協(xié)調(diào)服務器 ===");

        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

{

    // 配置參數(shù)

    private readonly string _serverIp;

    private readonly int _serverPort;

    private readonly string _clientId;

    

    // 網(wǎng)絡組件

    private TcpClient _tcpServerConnection;

    private NetworkStream _tcpStream;

    

    // 狀態(tài)變量

    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("已連接到協(xié)調(diào)服務器");


            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($"發(fā)送心跳失敗: {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. 部署協(xié)調(diào)服務器

P2PCoordinator.exe

2. 啟動被控端客戶端

P2PRdpClient.exe [服務器IP] ControlledPC

3. 啟動控制端客戶端

P2PRdpClient.exe [服務器IP] ControlPC

4. 建立P2P連接

在控制端輸入:

connect ControlledPC

5. 啟動遠程桌面

在控制端輸入:

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

技術(shù)實現(xiàn)細節(jié)

1. 端口轉(zhuǎn)發(fā)方案(被控端)

要讓遠程桌面通過P2P連接工作,需要在被控端設置端口轉(zhuǎn)發(fā)。以下是使用netsh設置端口轉(zhuǎn)發(fā)的批處理腳本:

被控端設置端口轉(zhuǎn)發(fā) (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 設置端口轉(zhuǎn)發(fā) (需要管理員權(quán)限)

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


echo 端口轉(zhuǎn)發(fā)已設置: %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遠程桌面服務

    • 運行端口轉(zhuǎn)發(fā)腳本(管理員權(quán)限)

    • 啟動客戶端:P2PRdpClient.exe server_ip ControlledPC

  2. 控制端操作:

    • 啟動客戶端:P2PRdpClient.exe server_ip ControlPC

    • 輸入:connect ControlledPC

    • 獲取被控端公網(wǎng)IP和端口

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

  3. 網(wǎng)絡穿透:

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

    • 被控端的端口轉(zhuǎn)發(fā)將流量轉(zhuǎn)到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


# 自動檢測監(jiān)聽的端口

$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 可用"

        

        # 設置端口轉(zhuǎn)發(fā)

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

        

        # 添加防火墻規(guī)則

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

        

        Write-Host "已設置端口轉(zhuǎn)發(fā): ${ipAddress}:${port} -> 127.0.0.1:3389"

        break

    }

    catch {

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

    }

}

2. NAT穿透優(yōu)化

對于復雜NAT環(huán)境,可使用以下增強穿透技術(shù):

// 在客戶端中添加

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)

    • 如果使用其他端口,需相應調(diào)整防火墻設置

  2. 網(wǎng)絡要求:

    • 被控端需要允許入站RDP連接

    • 控制端需要出站訪問協(xié)調(diào)服務器和P2P端口

  3. 安全建議:

    • 使用強密碼保護遠程桌面賬戶

    • 考慮使用VPN進行更安全的連接

    • 限制可連接IP地址范圍

  4. 權(quán)限要求:

    • 端口轉(zhuǎn)發(fā)腳本需要管理員權(quán)限

    • RDP服務需要啟用

這個方案直接利用Windows內(nèi)置的遠程桌面功能,通過P2P連接實現(xiàn)直連,避免了在應用中重新實現(xiàn)遠程桌面協(xié)議,既高效又可靠。


該文章在 2025/6/24 10:27:03 編輯過

全部評論1

admin
2025年6月24日 10:37
 相關(guān)教程:

C#實現(xiàn)混合P2P點對點直接連接方案(TCP + UDP),如果TCP連接失敗則改用UDP連接[28]
  http://31815.oa22.cn

該評論在 2025/6/24 10:37:07 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調(diào)度、堆場、車隊、財務費用、相關(guān)報表等業(yè)務管理,結(jié)合碼頭的業(yè)務特點,圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
天天爱天天做久久狠狠做 | 亚洲欧美日韩中文在线不卡网 | 香蕉伊蕉中文在线视频播放 | 亚洲日本中文字幕天天更新 | 在线观看中文字幕dvd播放 | 亚洲AV香蕉精品一区二区三区 |