0

I'm using UDP sockets to communicate a C++ application with a C# application.

In the C# -> C++ direction everything seems to be working fine, but the other way around is the one that's driving me nuts.

Communication does work, but messages are getting way late (like 2 secs delay) in the C# app, even though they're being sent every frame (it's a 3D app), and the receiving code is executing every 10 ms.

I need real time so this is a very painful problem. Do you think this might be related to packet losses? Then why don't they get lost in the other direction?

EDIT:

C# app code for syncing data:

 public void RecibeDatos() { if (MessageReceived && U != null && S != null) { MessageReceived = false; //Console.WriteLine("listening for messages"); U.BeginReceive(ReceiveCallback, S); } } public void ReceiveCallback(IAsyncResult ar) { UdpClient u = ((UdpState)(ar.AsyncState)).U; IPEndPoint e = ((UdpState)(ar.AsyncState)).E; receivedBytes = u.EndReceive(ar, ref e); //int currentProtocol = (int) numero; //ResetSignal = reset > 0; //Console.WriteLine("Received: " + currentProtocol); MessageReceived = true; } 

C++ Code for sending data:

 float indiceFloat[1]; indiceFloat[0] = indice_protocolo_actual; sender->setBuffer((void *)indiceFloat, sizeof(indiceFloat)); sender->sync(); 

sync method on J_Enviar (sender) class:

 void J_Enviar::sync( void ) { if(!_initialized) init(); if( _buffer == 0L ) { fprintf( stderr, "Broadcaster::sync() - No buffer\n" ); return; } #if defined (WIN32) && !defined(__CYGWIN__) unsigned int size = sizeof( SOCKADDR_IN ); sendto( _so, (const char *)_buffer, _buffer_size, 0, (struct sockaddr *)&saddr, size ); int err = WSAGetLastError (); if (err!=0) fprintf( stderr, "Broadcaster::sync() - error %d\n",err ); #else unsigned int size = sizeof( struct sockaddr_in ); sendto( _so, (const void *)_buffer, _buffer_size, 0, (struct sockaddr *)&saddr, size ); #endif } 

Providing full SocketManager code for Receiving C# end:

using System; using System.Net; using System.Net.Sockets; namespace WpfApplication1 { public class SocketManager { private static SocketManager _instance = null; static readonly object Padlock = new object(); private IPEndPoint E; private UdpClient U; private UdpState S; private byte[] receivedBytes; public static bool MessageReceived = true; private SocketManager() { } public byte[] ReceivedBytes { get { return receivedBytes; } } public static SocketManager Instance { get { lock(Padlock) { return _instance ?? (_instance = new SocketManager()); } } } public void CreateReceivingSocket(IPAddress a, int puerto) { if(E==null || (E.Address != a && E.Port != puerto)) { E = new IPEndPoint(a, puerto); U = new UdpClient(puerto); S = new UdpState { E = E, U = U }; } } public void ReceiveCallback(IAsyncResult ar) { UdpClient u = ((UdpState)(ar.AsyncState)).U; IPEndPoint e = ((UdpState)(ar.AsyncState)).E; receivedBytes = u.EndReceive(ar, ref e); //int currentProtocol = (int) numero; //ResetSignal = reset > 0; //Console.WriteLine("Received: " + currentProtocol); MessageReceived = true; } public void RecibeDatos() { if (MessageReceived && U != null && S != null) { MessageReceived = false; //Console.WriteLine("listening for messages"); U.BeginReceive(ReceiveCallback, S); } } public void CloseConnection() { if (E != null) { E.Port = 5502; E = null; } if (U != null) U.Close(); } } public class UdpState { public IPEndPoint E; public UdpClient U; } } 

And this is my dispatchertimerclick which makes the program receive each 10 ms:

 _dispatcherTimer.Tick += DispatcherTimerTick; _dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1); _dispatcherTimer.Start(); private void DispatcherTimerTick(object sender, EventArgs e) { _exp1Class.sendData(); _sm.RecibeDatos(); byte[] recibidos = _sm.ReceivedBytes; if (recibidos != null) { float numero = BitConverter.ToSingle(recibidos, 0); _exp1Class.CurrentProtocol = (int) numero; } } 
6
  • 1
    There is something you are doing wrong and you don't provide any details/code to figure out what the problem can be related to. Commented Jan 10, 2012 at 13:14
  • 2
    Check the raw packages with a program like Wireshark. That will help you determine where the actual delay might be. Commented Jan 10, 2012 at 13:15
  • 1
    Can you provide the code you use to receive on the C# side? Also you could benefit from running a Wireshark trace to prove what is happening at the packet level. Commented Jan 10, 2012 at 13:17
  • edited to provide code. hope that's enough, I can post more code if it's not. Will check Wireshank now :) Commented Jan 10, 2012 at 13:21
  • Okay, Wireshark proves that data is being sent properly, without delay. It's the receiver end which isn't working properly, then... Commented Jan 10, 2012 at 13:37

1 Answer 1

1

I don't see when you kick off your first BeginReceive. (Ah, it is done from your first timer tick I think?) It should be initaited as soon as you are ready to receive data. Secondly, your ReceiveCallback should take the received data and place it into a queue of some sort and immediately call BeginReceive again. Otherwise you are holding up thge arrival of the next data frame until the prior was consumed. Finally, watch for threading issues, as the Threading timer and the UDP callback each will run on seperate threads from your application main thread.

The only reason your code works at all is because you pre-initialized MessageReceived = true even before you receive any callbacks. When the first tick happens the call to RecibeDatos invokes BeginReceive because that bool was set to true.

Think of BeginReceive as saying "call me back when you have some data from the network". You don't need to poll the network using your timer. (You can choose to consume that data via your timer if your application requires that, but lets leave that aside for the moment).

Here are the rough steps:

First, upon start (or enable, run, etc) you should call BeginReceive. You will now receive a notification when data arrives.

Secondly, when the callback happens you complete that read of the data bytes using EndReceive. That data would typically be buffered or otherwise dispatched. You should then call BeginReceive again (within the callback) so that upon the next set of data being available you will again get notified. It becomes a kind of async loop.

The question is what to do with the data you are reading. You might consider placing the data into a queue, and then having your Timer pop these data frames off of the queue for processing. Be aware that the data can arrive multiple times between your Ticks.

Sign up to request clarification or add additional context in comments.

4 Comments

I call function RecibeDatos() on each timer tick. You mean I should call BeginReceive from the callback itself?
@kelmer Do you need any more clarification?
Sorry,I've been out of town for a few days! Thanks for your answer. When you say a queue, you mean like using a stack or something to store the data, then popping them in strict order, for instance? Wouldn't that make the program lose synchrony with the data being sent?
Well, a queue would be FIFO (first-in-first-out) which means you would process them in order. You do not need to use a queue if you can process the UDP data quickly enough in the callback. It might help if you further elaborated more on the "protocol" you are trying to use. You should be aware that UDP is "unreliable", so hopefully you take into account that some might be missing, out of order, or dupliacted.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.