3

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();
    }

}`

WEFX
  • 8,298
  • 8
  • 66
  • 102
Sandeep
  • 320
  • 2
  • 4
  • 18
  • why do you need this? is their no send/receive buffer flush command? //Need to create new object every time we start discovery because //every time udp buffer needs to be flushed and restarted sock = new UdpClient(); – hamish Sep 27 '14 at 00:07
  • I know this is an old thread - but did you ever find a fix? I have this issue now. – Mike Christiansen Sep 26 '15 at 15:42

3 Answers3

1

Why do you need Thread.Sleep?

It might cause the delays.

Alex Aza
  • 76,499
  • 26
  • 155
  • 134
  • Should be a comment. Please delete. – the_drow May 17 '11 at 07:52
  • @the_drow - Why? Sandeep asks why it is slow. The This could be the answer. If there is a big fragmented packet and if every fragment is received with a delay. – Alex Aza May 17 '11 at 07:58
  • @AlexAza: Are you sure that's the only reason it's slow? I'm not. In fact, it might make sense. You haven't suggested any solution to the problem. In order to find out why he uses `Thread.Sleep()` you should have asekd him using a comment. You can't answer something you don't know yourself. – the_drow May 17 '11 at 08:04
  • @alex: I won't -1 you - but why - he says that he has 2-3 minute delay - obviously using 100ms sleep won't accumulate to 2-3 minutes unless he has several thousands peers that will respond to the request. – Daniel Mošmondor May 17 '11 at 08:26
  • @Daniel 2 min is 1200 packets in this cases, I don't know how big message is received, I don't know how big is the send buffer on client side. The packets can fragment a lot, which will result one message sent as one big chunk arrive as a lot of small messages. – Alex Aza May 17 '11 at 08:34
  • 1
    Thread.Sleep() is required to give some gap between receive calls, without it, i won't get any packets it needs some delay. But I don't think that is the issue, I am getting delay 2-3 min – Sandeep May 17 '11 at 08:44
  • Getting the delay where? Seems to me like your looping on BeginReceive which can result in alot of calls to Thread.Sleep. Try and figure out where the delays are produced. Possibly use a profiler for this or just do some manual debugging/add some timers – Polity May 17 '11 at 09:25
1

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.

lennartk
  • 106
  • 6
0

you could use a timeout with a blocking call like this instead... because it appears your program does not want to do any other work whilst it waits anyway.. this way if the response comes in less than 100ms you don't have to wait that long.

udpAdmin.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 100)
receiveBytes = sock.Receive(RemoteIpEndPoint)  'waits here till you get a response or until timeout, whichever comes first.
hamish
  • 1,141
  • 1
  • 12
  • 21