0

I use this code for receiving scanlines:

StateObject stateobj = (StateObject)ar.AsyncState;
stateobj.workSocket.BeginReceive(new System.AsyncCallback(VideoReceive), stateobj);
UdpClient client = stateobj.workSocket;

IPEndPoint ipendp = new IPEndPoint(IPAddress.Any, 0);
byte[] data = client.EndReceive(ar, ref ipendp);


    BinaryReader inputStream = new BinaryReader(new MemoryStream(data));
    inputStream.BaseStream.Position = 0;
    int currentPart = inputStream.ReadInt32();


    if (currentPart == part)
    {
        int a = 0;
        int colum = inputStream.ReadInt32();
        for (; a < packets.GetLength(1); a++)
        {
            packets[colum, a, 2] = inputStream.ReadByte();
            packets[colum, a, 1] = inputStream.ReadByte();
            packets[colum, a, 0] = inputStream.ReadByte();
        }
        receiverCheck++;

    }
    else if (currentPart != part)
    {

        part++;
        mask2.Data = packets;

        pictureBox1.BeginInvoke(new MethodInvoker(() => { pictureBox1.Image = mask2.ToBitmap(); }));
        int colum = inputStream.ReadInt32();
        for (int a = 0; a < packets.GetLength(1); a++)
        {
            packets[colum, a, 2] = inputStream.ReadByte();
            packets[colum, a, 1] = inputStream.ReadByte();
            packets[colum, a, 0] = inputStream.ReadByte();
        }
    }

After all scanlines have been received the image displayed in pictureBox.

This should work, but have a lot lost packets even on localhost (only ~ 95 of 480), so I have striped image. I found a similar problem here. Answer:

private void OnReceive(object sender, SocketAsyncEventArgs e)
{
TOP:
    if (e != null)
    {
        int length = e.BytesTransferred;
        if (length > 0)
        {
            FireBytesReceivedFrom(Datagram, length, (IPEndPoint)e.RemoteEndPoint);
        }
        e.Dispose(); // could possibly reuse the args?
    }
    Socket s = Socket;
    if (s != null && RemoteEndPoint != null)
    {
        e = new SocketAsyncEventArgs();
        try
        {
            e.RemoteEndPoint = RemoteEndPoint;
            e.SetBuffer(Datagram, 0, Datagram.Length); // don't allocate a new buffer every time
            e.Completed += OnReceive;
            // this uses the fast IO completion port stuff made available in .NET 3.5; it's supposedly better than the socket selector or the old Begin/End methods
            if (!s.ReceiveFromAsync(e)) // returns synchronously if data is already there
                goto TOP; // using GOTO to avoid overflowing the stack
        }
        catch (ObjectDisposedException)
        {
            // this is expected after a disconnect
            e.Dispose();
            Logger.Info("UDP Client Receive was disconnected.");
        }
        catch (Exception ex)
        {
            Logger.Error("Unexpected UDP Client Receive disconnect.", ex);
        }
    }
}

Answer has method FireBytesReceivedFrom(), but I can't find it. How can I use this code? And does this code help?

Community
  • 1
  • 1
konstantin_doncov
  • 2,725
  • 4
  • 40
  • 100
  • 1
    UDP doesn't guarantee packet delivery. Out of 480 packets, are you losing or receiving 95 of them? It's ambiguous as written. – Chris Laplante Feb 19 '14 at 17:58
  • @ChrisLaplante receiving 95 packets. I think problem in the wrong memory usage or something like this. Anyway, I probably have an answer, but can't find method FireBytesReceivedFrom(). – konstantin_doncov Feb 19 '14 at 18:31

1 Answers1

1

UDP doesn't guarantee that all packets will be received, it that they will arrive in any particular order. So even if you get this "working" be aware that it could (will probably) fail at some point.

When you call BeginReceive, you are starting an sync read. When data arrives, your event handler will be called, and it is then that you need to call EndReceive. Currently you are calling EndReceive immediately, which is probably why things are going wrong.

Some other notes:

I'd suggest that you don't try to be clever and re-use the buffer, as that could result in you losing data by overwriting data while you are trying to read it. Start off simple and add optimizations like this after you have it working well.

Also, the goto could be causing havoc. You seem to be trying to use it to retry, but this code is running IN the data received event handler. Event handlers should handle the event in the most lightweight way possible and then return, not start looping... especially as the loop here could cause a re-entrant call to the same event handler.

With async comms, you should start a read and exit. When you eventually receive the data (your event handler is called), grab it and start a new async read. Anything more complex than that is likely to cause problems.

The Fire... method you are missing probably just raises (fires) an event to tell clients that the data has arrived. this is the place where you should be grabbing the received data and doing something with it.

If you are using an example to build this code then I suggest you look for a better example. (in any case I would always recommend trying to find 3 examples so you can compare the implementations, as you will usually learn a lot more about something this way)

Jason Williams
  • 56,972
  • 11
  • 108
  • 137
  • How can I calling EndReceive not immediately if I need to get packet? And can you give me code example because I'm not good at english. so, implement your advice in code is very difficult for me. Thanks! – konstantin_doncov Feb 21 '14 at 00:53
  • You start receiving. When data is received, your event handler is called. Then you call EndReceive to finish getting the data. You can't force the data to arrive earlier by calling EndReceive, you call it in reaction to the Data arriving. – Jason Williams Feb 21 '14 at 14:35
  • I understood that the problem in the wrong call endReceive. When should I call it and how? – konstantin_doncov Feb 22 '14 at 02:32
  • I've explained when to call it - in your DataReceived event handler. Please read the example from the documentation as a starting point: http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.endreceive(v=vs.110).aspx – Jason Williams Feb 22 '14 at 15:19
  • Oh, it's my fault. My first code block is an event handler function. Sorry for the confusion! – konstantin_doncov Feb 23 '14 at 01:05
  • I still have this issue. Do you have another solutions to the problem? Maybe I need to use SocketAsyncEventArgs class? – konstantin_doncov Feb 24 '14 at 18:12
  • Have you tried the example code from the link I posted in my previous comment? Or searched the net for other examples and tutorials on this subject? Try these to get basic communication working. Then try adding little bits of functionality to build towards your final goal of transmitting and displaying images. Don't run before you can walk. – Jason Williams Feb 24 '14 at 23:59
  • Yes, I tried. Now I do not even read the messages, simply increments the counter after each received message. The more buffer size, the less packets received. – konstantin_doncov Feb 25 '14 at 02:17
  • I do not used buffers for reading in a new test project(just increments the counter after each received packet), only to send the data. Also, if after each sending thread sleeps at least 1 millisecond, then all packets arrive. Graph of received packets as a function of buffer size is a hyperbola (the more buffer size, the less packets received). – konstantin_doncov Feb 25 '14 at 23:10
  • If you re-use any of your buffers for sending, you may be overwriting the data while the UDPClient is trying to access the data in the buffer and thus sending corrupt packets or seeming to skip packets. By adding Sleep(1) you would cause your thread to yield, allowing the UDPClient's thread to finish using the buffer before you overwrite it, thus "hiding" the problem. Make sure you are not re-using any buffers, and try to start with the simplest possible case (send single integers 1,2,3,4 instead of video scanlines...) to eliminate as many possible sources of errors as you can. – Jason Williams Feb 25 '14 at 23:52