基于C#編寫一個(gè)遠(yuǎn)程桌面應(yīng)用
背景
封閉環(huán)境無法拷貝外來的遠(yuǎn)程桌面軟件,所以就直接自己用C#寫一個(gè)。
效果

說明
本篇會(huì)給出完整的編程步驟,照著寫就能擁有你自己的遠(yuǎn)程桌面應(yīng)用,直接可以運(yùn)行在局域網(wǎng)。
如果不想自己敲代碼,也可以選擇直接下載項(xiàng)目資源,解包后直接用VS2019打開即可運(yùn)行或自行打包成exe
設(shè)計(jì)
遠(yuǎn)程桌面需要一個(gè)服務(wù)端,一個(gè)客戶端,各自是一個(gè)項(xiàng)目文件。
本項(xiàng)目中客戶端分享畫面(發(fā)送截屏數(shù)據(jù)流),服務(wù)端則是監(jiān)聽并接收畫面,因此服務(wù)端需要兩個(gè)Form(窗體)。
項(xiàng)目源碼
客戶端UI
只需要一個(gè)Form1,布局如下:

具體組件和屬性設(shè)置如下:
- Label1,text改為IP即可;
- Label2,text改為Port即可;
- textbox1,名稱改為txtIP;
- textbox2,名稱改為txtPort,text改為80
- button1,text改為Connect,名稱改為btnConnect
- button2,text改為ShareScreen,名稱改為btnShare
客戶端源碼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Drawing.Imaging;
using System.Runtime.Serialization.Formatters.Binary;
namespace OriginalClient
{
public partial class Form1 : Form
{
private readonly TcpClient client = new TcpClient();
private NetworkStream mainStream;
private int portNumber;
private static Image GrabDesktop()
{
Rectangle bound = Screen.PrimaryScreen.Bounds;
Bitmap screenshot = new Bitmap(bound.Width, bound.Height, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(screenshot);
graphics.CopyFromScreen(bound.X, bound.Y, 0, 0, bound.Size, CopyPixelOperation.SourceCopy);
return screenshot;
}
private void SendDesktopImage()
{
BinaryFormatter binFormatter = new BinaryFormatter();
mainStream = client.GetStream();
binFormatter.Serialize(mainStream, GrabDesktop());
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
btnShare.Enabled = false;
}
private void btnConnect_Click(object sender, EventArgs e)
{
portNumber = int.Parse(txtPort.Text);
try
{
client.Connect(txtIP.Text, portNumber);
btnConnect.Text = "Connected";
MessageBox.Show("Connected");
btnConnect.Enabled = false;
btnShare.Enabled = true;
}
catch (Exception)
{
MessageBox.Show("Failed to connect");
btnConnect.Text = "Not Connected";
}
}
private void btnShare_Click(object sender, EventArgs e)
{
if (btnShare.Text.StartsWith("Share"))
{
timer1.Start();
btnShare.Text = "Stop Sharing";
}
else
{
timer1.Stop();
btnShare.Text = "Share My Screen";
}
}
private void timer1_Tick(object sender, EventArgs e)
{
SendDesktopImage();
}
}
}
服務(wù)端UI Form1

- textBox1,name設(shè)置為txtPort
- button1,name設(shè)置為btnListen
Form1代碼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace OriginalServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnListen_Click(object sender, EventArgs e)
{
new Form2(int.Parse(txtPort.Text)).Show();
btnListen.Enabled = false;
}
}
}
Form2
源項(xiàng)目中追加一個(gè)窗體。
一個(gè)窗體里放一個(gè)imageBox,mode設(shè)置為zoom,dock設(shè)置為??俊?/p>
Form2源碼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;
namespace OriginalServer
{
public partial class Form2 : Form
{
private readonly int port;
private TcpClient client;
private TcpListener server;
private NetworkStream mainStream;
private readonly Thread Listening;
private readonly Thread GetImage;
public Form2(int Port)
{
port = Port;
client = new TcpClient();
Listening = new Thread(StartListening);
GetImage = new Thread(Receiveimage);
InitializeComponent();
}
private void StartListening()
{
while (!client.Connected)
{
server.Start();
client = server.AcceptTcpClient();
}
GetImage.Start();
}
private void StopListening()
{
server.Stop();
client = null;
if (Listening.IsAlive) Listening.Abort();
if (GetImage.IsAlive) Listening.Abort();
}
private void Receiveimage()
{
BinaryFormatter binFormatter = new BinaryFormatter();
while (client.Connected)
{
mainStream = client.GetStream();
pictureBox1.Image = (Image)binFormatter.Deserialize(mainStream);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
server = new TcpListener(IPAddress.Any, port);
Listening.Start();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
StopListening();
}
private void pictureBox1_Click(object sender, EventArgs e)
{
}
private void Form2_Load(object sender, EventArgs e)
{
}
}
}到此這篇關(guān)于基于C#編寫一個(gè)遠(yuǎn)程桌面應(yīng)用的文章就介紹到這了,更多相關(guān)C#遠(yuǎn)程桌面內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#使用StopWatch獲取程序毫秒級(jí)執(zhí)行時(shí)間的方法
這篇文章主要介紹了C#使用StopWatch獲取程序毫秒級(jí)執(zhí)行時(shí)間的方法,涉及C#操作時(shí)間的相關(guān)技巧,需要的朋友可以參考下2015-04-04
C#實(shí)現(xiàn)將DataTable快速導(dǎo)出為Word表格
在現(xiàn)代C#應(yīng)用開發(fā)中,將程序數(shù)據(jù)以結(jié)構(gòu)化的形式導(dǎo)出為用戶友好的Word文檔是一項(xiàng)常見的需求,下面我們來看看C#如何使用Spire.Doc for .NET庫實(shí)現(xiàn)將DataTable中的數(shù)據(jù)導(dǎo)出到Word文檔2026-01-01
Unity游戲腳本開發(fā)的生命周期函數(shù)詳解(Update/FixedUpdate)
本文介紹了Unity游戲開發(fā)中腳本的生命周期函數(shù)Update/FixedUpdate的核心概念、技術(shù)原理、應(yīng)用場(chǎng)景、實(shí)踐應(yīng)用、常見問題與解決方案及最佳實(shí)踐等內(nèi)容,通過學(xué)習(xí),可以掌握關(guān)鍵技術(shù)要點(diǎn),提升游戲開發(fā)效率和項(xiàng)目質(zhì)量2026-05-05
WPF實(shí)現(xiàn)帶篩選功能的DataGrid
在默認(rèn)情況下,WPF提供的DataGrid僅擁有數(shù)據(jù)展示等簡(jiǎn)單功能,如果要實(shí)現(xiàn)像Excel一樣復(fù)雜的篩選過濾功能,則相對(duì)比較麻煩。本文以一個(gè)簡(jiǎn)單的小例子,簡(jiǎn)述如何通過WPF實(shí)現(xiàn)DataGrid的篩選功能,僅供學(xué)習(xí)分享使用,如有不足之處,還請(qǐng)指正2023-03-03
C#實(shí)現(xiàn)Base64編碼與解碼及規(guī)則
這篇文章主要介紹了C#實(shí)現(xiàn)Base64編碼與解碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08
c# GridControl的模糊查詢實(shí)現(xiàn)代碼
這篇文章主要介紹了c# GridControl的模糊查詢實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-02-02

