1

I have a goal of send and receive screenshots continuously using Asyncronous socket and created this following code after see several references on web. Before try send continuously i tested sending only one time, but screenshot not is received correctly on server.

Some idea about how fix it? Thanks in advance.

Server:

Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text

Public Class frmServer
    Dim serverSocket As Socket
    Dim clientSocket As Socket
    Dim byteData(1023) As Byte

    Private Sub FrmServer_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        serverSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        Dim IpEndPoint As IPEndPoint = New IPEndPoint(IPAddress.Any, 8800)
        serverSocket.Bind(IpEndPoint)
        serverSocket.Listen(5)
        serverSocket.BeginAccept(New AsyncCallback(AddressOf OnAccept), Nothing)
    End Sub

    Private Sub OnAccept(ByVal ar As IAsyncResult)
        clientSocket = serverSocket.EndAccept(ar)
        'New connection established
        clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, New AsyncCallback(AddressOf OnReceive), clientSocket)
        serverSocket.BeginAccept(New AsyncCallback(AddressOf OnAccept), Nothing)
    End Sub

    Private Sub OnReceive(ByVal ar As IAsyncResult)
        Dim client As Socket = ar.AsyncState
        client.EndReceive(ar)

        'Using MStream As New MemoryStream(byteData)
        'Dim returnImage As Image = Image.FromStream(MStream)
        'pbDesktop.Image = returnImage
        'End Using

        File.WriteAllBytes(Environment.CurrentDirectory & "\screenshot.jpg", byteData)

        'Array.Clear(byteData, 0, byteData.Length)
        clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, New AsyncCallback(AddressOf OnReceive), clientSocket)
    End Sub

Client:

Imports System.Drawing.Imaging
Imports System.IO
Imports System.Net
Imports System.Net.Sockets

Public Class frmClient

    Private Function BytesScreen() As Byte()
        Dim bounds As Rectangle
        Dim screenshot As Bitmap
        Dim graph As Graphics
        bounds = Screen.PrimaryScreen.Bounds
        screenshot = New Bitmap(bounds.Width, bounds.Height)
        graph = Graphics.FromImage(screenshot)
        graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy)

        Dim ms As New MemoryStream()
        screenshot.Save(ms, ImageFormat.Jpeg)
        Dim bitmapbytestream(ms.Length) As Byte
        bitmapbytestream = ms.ToArray

        Return bitmapbytestream
    End Function

    Dim clientSocket As Socket

    Private Sub BtnConnect_Click(sender As Object, e As EventArgs) Handles btnConnect.Click
        clientSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        Dim IpAddress As IPAddress = IPAddress.Parse("127.0.0.1")
        Dim IpEndPoint As IPEndPoint = New IPEndPoint(IpAddress, 8800)
        clientSocket.BeginConnect(IpEndPoint, New AsyncCallback(AddressOf OnConnect), Nothing)
    End Sub

    Private Sub OnConnect(ByVal ar As IAsyncResult)
        clientSocket.EndConnect(ar)
        Send(BytesScreen, clientSocket)
    End Sub

    Private Sub Send(ByVal byteData As Byte(), ByVal client As Socket)
        Try
            client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, New AsyncCallback(AddressOf OnSend), client)
        Catch ex As Exception
            If Not client.Connected Then 'if connection was forcibly disconnected
                'reconnecting to the server
                btnConnect.PerformClick()
            End If
        End Try
    End Sub

    Private Sub OnSend(ByVal ar As IAsyncResult)
        Dim client As Socket = ar.AsyncState
        client.EndSend(ar)
        'Send(BytesScreen, clientSocket)
    End Sub

End Class
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
FLASHCODER
  • 1
  • 7
  • 24
  • 1
    The first, most apparent issue is that your server reads at most 1 KB of data (1024 bytes) at a time. Most images are larger than that, however it isn't as simple as increasing the buffer size since you don't know how much data each `Receive` call will give you. TCP is a stream-based protocol, meaning at the application layer all data is presented in a continuous stream of bytes and you only receive what you've downloaded so far. Thus one call to `Send` may require several calls to `Receive` depending on the size of your data. – Visual Vincent Mar 05 '20 at 19:48
  • What you need is something to tell you where the pieces of data begins and ends. The easiest, yet very robust solution is called _length-prefixing_, which you can read more about in [an earlier answer of mine](https://stackoverflow.com/a/37352525) with an example implementation [in another](https://stackoverflow.com/a/35240061). – Visual Vincent Mar 05 '20 at 19:58
  • (Sorry, had to split this into several comments) How you decide to use this depends on what you need. If you're just sending one file at a time and nothing else in-between you _could_ send everything in one "packet", but if you need to send other kinds of data without waiting for the entire file to be sent you should divide your file into several small packets and send them one-by-one. I tend to divide files into packets of 8192 bytes (8 KB), as based on my experience it provides a good ratio between speed and latency over a wide range of different connection speeds. – Visual Vincent Mar 05 '20 at 19:59
  • @VisualVincent, is `BeginReceive()` and `BeginSend()`, are async sockets and not sync sockets :D. Thank your explanation on comments above, they will be useful to someone that use sync sockets. – FLASHCODER Mar 05 '20 at 20:41
  • 1
    I think you've misunderstood... Length-prefixing is merely a way to denote where a piece of data begins and ends. It doesn't matter whether you use the sockets synchronously or asynchronously, you still need to know how much data there is to receive and where you're currently reading at in relation to the rest of it. When I said `Send` and `Receive` I wasn't referring to the synchronous methods but rather to any time you perform a send or receive operation on the stream, asynchronous or not. – Visual Vincent Mar 05 '20 at 21:10
  • "*`but if you need to send other kinds of data without waiting for the entire file to be sent`*" - Yes this also is the goal. – FLASHCODER Mar 05 '20 at 21:10
  • While my example implementation in the second answer is old and based on synchronous methods utilizing threads, it is perfectly possible to do this using asynchronous calls as well. It's just a matter of preserving state - i.e. keeping track of which packet you're receiving data for. The last parameter of `BeginRead()` and `BeginSend()` (in which you specify `clientSocket`) is used to do so. Although, I would rather recommend the `ReadAsync()` and `SendAsync()` methods as those let you utilize asynchronousity but still retain a cleaner, synchronous-like code style. – Visual Vincent Mar 05 '20 at 21:20
  • @VisualVincent, already make some time that i try (a code own mine) async sockets works sending and receiving any data type correctly, but until now without success. Already to syncronous socket all seems more easy and with several references on web :D. – FLASHCODER Mar 05 '20 at 21:54
  • Try the `ReadAsync()` and `WriteAsync()` of the [`NetworkStream`](https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.networkstream) together with [`Await`](https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/await-operator) if you use any Visual Studio version newer than 2010. They're made to let your code keep its regular top-down flow whilst still being asynchronous and not interrupting the calling thread. – Visual Vincent Mar 05 '20 at 22:37
  • @VisualVincent, "*`however it isn't as simple as increasing the buffer size`*" - increasing buffer size worked (**`Dim byteData(81927657) As Byte`**). "*`since you don't know how much data each Receive call will give you.`*" - How discover it? some idea? – FLASHCODER Mar 06 '20 at 01:10
  • "*`since you don't know how much data each Receive call will give you.`*" - I think that [this](https://stackoverflow.com/a/6887192/9708179) can solve. Also [here](https://social.msdn.microsoft.com/Forums/vstudio/en-US/7f690da0-3a07-45b9-b342-cea77760b5d1/asynchronous-client-server-image-sending-c?forum=csharpgeneral) can see a code example based on first link of @Mike's answer. – FLASHCODER Mar 06 '20 at 03:50
  • That's great, however you do realize you just found three different links that all describe length-prefixing? They're similar to my answers, only with slight variations. It's a good thing, though, because that means you now have a lot of research material. :) – Visual Vincent Mar 06 '20 at 06:23

0 Answers0