📜 ⬆️ ⬇️

We write smart Remote - Desktop client on C # and XNA

Hi, I'll show you how to write a Remote - Desktop client using C # + XNA


This topic inspired me to write this article.

A bit of myself


I waited a long time for the second part of that article, but I did not wait. As the author argued, the second article was supposed to be the implementation of image transmission via UDP protocol to a remote client. After that I tried to implement the second part of the article myself, but it always turned out badly. Due to the slow drawing of the GDI, the program simply hung on the computer Core 2 Duo 2.66 GHz, Nvidia GeForce 9600 GT . I used different optimization algorithms, but it didn't help much and then I decided to use XNA.

Selection of transmission protocol


I wanted very much to choose the TCP transfer protocol, there are fewer problems with it, but I chose UDP, because everyone says that it is better for such cases to take blah blah blah ... You’re probably wondering why there are more problems with UDP? The answer is simple - a UDP message cannot exceed 65,507 bytes in size, which is not very convenient. Our packets average 130,000 bytes in size (for a screen size of 1366x768), when we try to send such a packet, an error occurs, as shown below.

')
This problem can be solved in two ways:
1) Create a crutch
2) Create a structure

1) Since I'm lazy, I chose a crutch. The crutch is to break a larger message into many small ones and write the number of pieces in the first message that will be sent. I called it a crutch, because, having lost the first message, the program will fly to hell to not properly glue the image (it will not know how many parts the image is broken into).

2) You can break the screen into many pieces and remember their coordinates. All this will need to be stored in the structure, which is very convenient, by the way, this algorithm will help to make optimization in the future.

Practice


I'll start with a simple one. From the sender. We will send screenshots of our screen to a remote computer. I wrote a function for loading data and initializing some variables.

The launch point is our Run () function.
public void Run() { Load(); //       udpClient = new UdpClient(); Bitmap BackGround = new Bitmap(width, height); Graphics graphics = Graphics.FromImage(BackGround); while (true) { //    graphics.CopyFromScreen(0, 0, 0, 0, new Size(width, height)); //       byte [] bytes = ConvertToByte(BackGround); List<byte[]> lst = CutMsg(bytes); for (int i = 0; i < lst.Count; i++) { //    udpClient.Send(lst[i], lst[i].Length, ipEndPoint); } } } 

Load () data is loaded first, variables are declared and looped. In the loop, we get the screen image, convert it to a byte array, use my crutch (splitting the message into several messages - CutMsg (bytes)), send all the packets.

Nothing interesting happens in the Load () function.
Two lines will be read from the ip.txt file. The first line is the IP address to which you want to send data. The second line is the Port to which the sending will occur. Also there will be getting the length and width of the screen.

Conversion function
 private byte [] ConvertToByte(Bitmap bmp) { MemoryStream memoryStream = new MemoryStream(); //       Jpeg bmp.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg); return memoryStream.ToArray(); } 


And the most interesting is the implementation of the crutch.
 private List<byte[]> CutMsg(byte[] bt) { int Lenght = bt.Length; byte[] temp; List<byte[]> msg = new List<byte[]>(); MemoryStream memoryStream = new MemoryStream(); //    2    memoryStream.Write( BitConverter.GetBytes((short)((Lenght / 65500) + 1)), 0, 2); //     memoryStream.Write(bt, 0, bt.Length); memoryStream.Position = 0; //      -   while (Lenght > 0) { temp = new byte[65500]; memoryStream.Read(temp, 0, 65500); msg.Add(temp); Lenght -= 65500; } return msg; } 

I share the data on blocks of 65,500 (the number took less to clearly get) and write them to the sheet of byte arrays, after I return this sheet.

Recipient Code


It’s more complicated with the recipient, I used delegates and events there for asynchronous work and I don’t want to bore you with code that I’ll write the main thing.

Asynchronous data retrieval.
 int countErorr = 0; private void AsyncReceiver() { IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0); while (true) { try { MemoryStream memoryStream = new MemoryStream(); byte[] bytes = udpClient.Receive(ref ep); memoryStream.Write(bytes, 2, bytes.Length - 2); int countMsg = bytes[0] - 1; if (countMsg > 10) throw new Exception("  "); for (int i = 0; i < countMsg; i++) { byte[] bt = udpClient.Receive(ref ep); memoryStream.Write(bt, 0, bt.Length); } GetData(memoryStream.ToArray()); memoryStream.Close(); } catch { countErorr++; } } } 

We again see the looping, then we get the first packet, we read the first byte from it (the number of future messages is written in this byte), if the message is longer than 10, we obviously lost the first packet, therefore we add the loss counter, otherwise we get all the messages - we glue them into one and raise the GetData event (byte []).

In GetData (byte []) we get Texture2D, converting it from an array of bytes.
 private void Receive_GetData(byte[] Date) { BackGround = ConvertToTexture2D(Date); } private Texture2D ConvertToTexture2D(byte[] bytes) { MemoryStream memoryStream = new MemoryStream(bytes); System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(memoryStream); //    .png,  Texture2D    memoryStream = new MemoryStream(); bmp.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png); //    Texture2D return Texture2D.FromStream(GraphicsDevice, memoryStream); } 


You can download the whole project at the end of the article, so do not despair if I have not written something.

Results and conclusion


As a result, when the “sender” and “receiver” are simultaneously launched, recursion and a huge amount of losses occur on their computer (30–90 losses), when the “sender” is started on my computer, and on the computer of the “receiver” parents, there is at least a loss (10 15 losses). Both computers (parents and mine) are connected to the same Wi-Fi network with a 54 Mbit / s channel. There is a ping (about 250 ms.) - reminds by ping TeamViewer. If you add optimization and replace the crutch, you get a great program for image transfer.

Recursion


Parents computer (image transfer from my computer to theirs)


What does a loss look like?


In the next article I will finish the program, or rather add the ability to remote control and maybe even optimize it.

Download project
Download Receiver (Receives Images)
Download Sender (Sends Images)

PS I reloaded the source code on github github.com/Luchanso/remote-desktop

Source: https://habr.com/ru/post/142617/


All Articles