0

I'm making my first screen sharing application in VB.NET using sockets to establish the connections.

This is the client side receiving screen images from the server (they are both running in a thread):

Private Sub startscreen()
    Using imgstream As NetworkStream = imgclient.GetStream()
        Using ms As New MemoryStream
            Dim read As Double
            Do
                If (imgstream.DataAvailable) Then
                    read = 0
                    ms.Seek(0, SeekOrigin.Begin)

                    While imgclient.Available
                        Dim buffer(imgclient.Available - 1) As Byte
                        imgstream.Read(buffer, 0, buffer.Length)
                        ms.Write(buffer, 0, buffer.Length)
                        read += buffer.Length
                    End While

                    Me.Text = "Frame bytes read: " & read
                    PictureBox1.Image = Image.FromStream(ms)
                    ms.Flush()
                 End If
                 Thread.Sleep(34) 'about 30 FPS
             Loop
        End Using
    End Using
End Sub

And this is the server side:

Private Sub screen()
    Using imgstream As NetworkStream = imgclient.GetStream()
        Using ms As New MemoryStream
            Do
                Thread.Sleep(34) 'about 30 FPS
                ms.Seek(0, SeekOrigin.Begin)
                Using img = ScreenCap()
                    img.Save(ms, Imaging.ImageFormat.Jpeg)
                End Using
                ms.WriteTo(imgstream)
            Loop
        End Using
    End Using
End Sub

Public Function ScreenCap() As Image
    Dim screenSize As Size = New Size(My.Computer.Screen.Bounds.Width, My.Computer.Screen.Bounds.Height)
    Dim screenGrab As New Bitmap(My.Computer.Screen.Bounds.Width, My.Computer.Screen.Bounds.Height) ', Imaging.PixelFormat.Format16bppRgb555)
    Dim g As Graphics = Graphics.FromImage(screenGrab)
    g.CopyFromScreen(New Point(0, 0), New Point(0, 0), screenSize)
    g.Dispose()
    Return screenGrab
End Function

The main problem is when I call the "Image.FromStream(ms)" function, it sometimes works and others doesn't depending on how many milliseconds I set the thread to wait. Tested on 2 different computers in my LAN, on around 1 second it seems OK but always with a high CPU-Network usage. If I set, as the example says around 34 milliseconds to get all more "LIVE", that function throw an exception because of the MemoryStream. How can I speed it up? Is there any smarter way I'm missing right now? I've also tried putting a delimiter byte (like a char = "*") at the and of the MemoryStream and then send it to the client who read one byte at a time until it found a char equal to the delimiter. But it turned out to be a bad solution because a single byte of the image could represent the delimiter if converted to char. Another question I have is: How can I change the image quality and the color depth? Is it a good approach using what the comment says: "Imaging.PixelFormat.Format16bppRgb555"

Thank you!

Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
Dadex
  • 119
  • 2
  • 12
  • I don't know what exception you're getting but I'm pretty sure it has to do with an incomplete image. You never state it, but it seems pretty obvious that you're using TCP. The golden rule to always remember with TCP is that _**it doesn't handle packets**_. The data you receive is streamed, therefore you're not very likely to receive all data in a single `Read()` call. You either receive too much data or too little. – Visual Vincent Feb 11 '17 at 10:51
  • You need a custom protocol which indicates the start and end of your data. As you said a delimiter won't do when dealing with non-plain text files. Instead you should implement _**length-prefixing**_ (aka _message framing_). Length-prefixing prefixes the data you send with the data's length, thus the receiver can read the size and know how much data it should read until it's received one "packet". I've described length-prefixing in this answer of mine: http://stackoverflow.com/a/37352525/3740093 – Visual Vincent Feb 11 '17 at 10:56
  • _**REMEMBER**_ that one `NetworkStream.Read()` call also isn't certain to read all the bytes you request, it only reads what is available at that time. Therefore you must check the return value of `Read()` in order to determine how much has actually been read everytime you call it. Use that to keep track of how much data you've received. – Visual Vincent Feb 11 '17 at 10:58

0 Answers0