Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UDPClient Async BeginReceive is very slow

I am using UDPClient to send multicast request and receive response from various clients on the network. I am able to send request and also getting response, but response that I get is very slow. It take 2-3 minutes to get response from all the clients. On send request on the network I checked in the WireShark, there I am seeing response in milliseconds from all the clients only in test program. It is taking lot of time. Can anyone guide what mistake I might be doing? Following is the code. Please guide me on this. I have been stuck on this issue for the last 2 days.

public class Trinity_WSDiscovery : IDiscoveryService 
{
        #region IDiscoveryService Members
        public event EventHandler FoundNewDevice;
        public event EventHandler EndOfDiscovery;
        DeviceBinding m_DeviceBinding;
        bool IsFindComplete = false;
        Thread receiveThread;
        UdpClient sock ;        
        IPEndPoint RemoteIpEndPoint = new IPEndPoint(System.Net.IPAddress.Any, 0);
        IPEndPoint iep = new IPEndPoint(System.Net.IPAddress.Parse("239.255.255.250"), 3702);
        UdpState udpState = new UdpState();
        XmlDocument xmlDoc = new XmlDocument();

    public void Start()
    {
        //Need to create new object every time we start discovery because
        //every time udp buffer needs to be flushed and restarted
        sock = new UdpClient();
        string str = "<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:d=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\" xmlns:wsadis=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" xmlns:dn=\"http://www.onvif.org/ver10/network/wsdl\"><soap:Header><wsadis:MessageID>uuid:" + System.Guid.NewGuid().ToString() + "</wsadis:MessageID><wsadis:To>urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsadis:To><wsadis:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsadis:Action></soap:Header><soap:Body><d:Probe><d:Types /> <d:Scopes/></d:Probe></soap:Body></soap:Envelope>";
        byte[] data = Encoding.ASCII.GetBytes(str);
        sock.Send(data, data.Length, iep);
        sock.JoinMulticastGroup(System.Net.IPAddress.Parse("239.255.255.250"));            
        IPEndPoint iep1 = new IPEndPoint(System.Net.IPAddress.Any, 0);            
        udpState.ipEndpt = RemoteIpEndPoint;
        udpState.udpClient = sock;           
        BeginReceive();           
    }

    public void BeginReceive()
    {
        Thread.Sleep(100);
        if (sock.Available > 0)
        {
            sock.BeginReceive(new AsyncCallback(ReceiveCallback), udpState);
        }
        else
        {
            FindComplete();
        }
    }

    public void ReceiveCallback(IAsyncResult ar)
    {
        UdpClient udpClient = (UdpClient)((UdpState)(ar.AsyncState)).udpClient;
        IPEndPoint ipEndpt = (IPEndPoint)((UdpState)(ar.AsyncState)).ipEndpt;
        Byte[] receiveBytes = udpClient.EndReceive(ar, ref ipEndpt);
        string receiveString = Encoding.ASCII.GetString(receiveBytes);
        if (receiveString.Contains("NetworkVideoTransmitter"))
        {
            xmlDoc.LoadXml(receiveString);
            XmlNodeList list = xmlDoc.GetElementsByTagName("XAddrs", "http://schemas.xmlsoap.org/ws/2005/04/discovery");
            XmlNode node = list[0];
            string strEndPoints = node.FirstChild.Value;
            string[] strEndPointList = Regex.Split(strEndPoints, " ");
            OnFoundDevice(strEndPointList);
        }
        BeginReceive();
    }

}`

like image 876
Sandeep Avatar asked Nov 18 '25 23:11

Sandeep


2 Answers

Why do you need Thread.Sleep?

It might cause the delays.

like image 180
Alex Aza Avatar answered Nov 20 '25 11:11

Alex Aza


I see two possible causes for your problem.

  1. It seems as you have built in a 100 ms delay for each response from each responding client in your design. The first thing you do in your BeginReceive method is to sleep, regardless if there is data or not. For each response, you (correclty) call BeginReceive to register your new receive callback. But since there is only one ReceiveCallback registered at a time, processing each response will take at least 100 ms. If you get 30 incoming client calls at the same time, the last one will thus be delayed 3 seconds.

  2. In your ReceiveCallback you call your method OnFoundDevice. This looks like a callback or event handler. Any execution time spent by this callback will delay the next processed answer. If the callback takes 1 minute, the next response will be delayed 1 minute (plus 100 ms in your BeginReceive method).

Suggested solution: 1. Remove delay and condition from your BeginReceive, like this.

public void BeginReceive()
{
     sock.BeginReceive(new AsyncCallback(ReceiveCallback), udpState);
}
  1. Review the work done by OnFoundDevice. If it is time consuming, marshal the call to another thread (by for example doing a QueueUserWorkItem on the threadpool).

If the reason you used sleep in your BeginReceive was to find a criteria on when to stop listening for data, you could launch a timer for this instead in your Start method and call Close on your socket after a predetermined time or when not having received data within a set timespan.

I hope this helps you out.

like image 44
lennartk Avatar answered Nov 20 '25 13:11

lennartk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!