Click here to Skip to main content
15,867,308 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I know this is a common question people ask but for days I have been researching and couldn't find a way that will help me.

I'm developing a screen sharing program and using TCP to send the desktop screenshots over the networkstream. I tried using UDP but later discovered that it has a message size limit of 65,507 bytes and I have way more bytes in a single message so I use TCP.

When I run the program I get some of the images and if the bytes size is increased then it while converting the bytes to image it throws

Exception thrown:
'System.ArgumentException' in System.Drawing.dll
System.ArgumentException: Parameter is not valid.

As far as I have read everywhere is networkstream takes time to read all the bytes sent from the server and if the server send another data before the networkstream finish the reading then the byte array will have insufficient data in it and hence it will throw the error. I also tried Thread.Sleep(milliseconds) but again I cannot predict the time to wait and it will make process much slower.

Is there any way I can wait for networkstream write to let networkstream read all the bytes that are sent and continue sending and waiting but this has to be fast as there are sets of images that combining makes a video in picturebox of client.

Code:

Server

C#
private void receiveScreenShare()
    {
        TcpListener list = new TcpListener(IPAddress.Parse("192.168.0.102"), 4567);
        list.Start();
        TcpClient client = list.AcceptTcpClient();
        NetworkStream streamScreenShare = client.GetStream();
        while (true)
        {
            try
            {
                byte[] bytes = new byte[1000000];
                streamScreenShare.Read(bytes, 0, bytes.Length);
                ImageConverter convertData = new ImageConverter();
                Image image = (Image)convertData.ConvertFrom(bytes); //Here is the error
                pictureBox1.Image = image;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    }


Client

C#
byte[] b1 = null;
    private void sendScreen()
    {
        try
        {
            TcpClient client = new TcpClient("192.168.0.102", 4567);
            while (true)
            {
                NetworkStream streamScreen = client.GetStream();
                //Get Screenshot
                Bitmap bm = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
                Graphics g = Graphics.FromImage(bm);
                g.CopyFromScreen(0, 0, 0, 0, bm.Size);
                //Convert Screenshot to byte
                Bitmap newBM = new Bitmap(bm, new Size(bm.Width / 2, bm.Height / 2));
                MemoryStream ms = new MemoryStream();
                bm.Save(ms, ImageFormat.Jpeg);
                //Write Screenshot into stream
                b1 = ms.ToArray();
                streamScreen.Write(b1, 0, b1.Length);
            
                Thread.Sleep(500);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }


What I have tried:

I have referred these questions too:
1. C# TCP Read All Data - Server Side Issues[^]

2. https://stackoverflow.com/questions/52439851/c-sharp-tcp-how-can-i-get-exacly-amount-of-bytes-that-are-recived[^]

Working with the methods stated in above solutions I have found that the networkstream tries to read the bytes but the client still sends data to the server and server goes into infinite loop because it's receiving data every millisecond.
Posted
Updated 4-Nov-22 11:41am

Try this CodeProject article: Windows Remote Desktop Application[^]
It probably has TCP routines you can use.
 
Share this answer
 
Comments
Member 14623639 5-Nov-22 0:32am    
Thanks for your solution but I tried using binary formatter method before and it's very slow process as it gives me 3fps on my local server and I can't imagine how slow it would process if I used a hosted server on the internet.
In addition to RickZeeland's comment, another important thing to remember when it comes to network/streaming is that there's no guarantee how many bytes you'll receive at any given time.
C#
byte[] bytes = new byte[1000000];
streamScreenShare.Read(bytes, 0, bytes.Length);

This is saying "fetch me up to 1,000,00 bytes". However, if there was any sort of network latency or connectivity problem you wouldn't be guaranteed to receive all of the bytes from the client. Network packets and be dropped and re-issued which might mean you could get a buffer containing 100 bytes, followed by another containing 32,100 bytes.

Some people work around this by creating a packet structure within their application. For example, the first 4 bytes of the stream might get decoded into an Int32 which has the length of the next image (in bytes). Then you could stream the image bytes and make sure to count how many you've received to ensure that you're getting the full picture. After you've successfully processed the image's bytes, you know the next 4 bytes would again be the next image length.
 
Share this answer
 
Comments
Member 14623639 5-Nov-22 0:30am    
but how can I work with while(true) in both write and read? As if I'm reading the chunked data received in a while loop get total number of bytes received but write keeps writing the data in the networkstream and this causes the chunk reading to go in infinite loop.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900