UDPClient Async BeginReceive очень медленный - PullRequest
3 голосов
/ 17 мая 2011

Я использую UDPClient для отправки многоадресного запроса и получения ответа от различных клиентов в сети. Я могу отправить запрос и получить ответ, но ответ, который я получаю, очень медленный. Требуется 2-3 минуты, чтобы получить ответ от всех клиентов. При отправке запроса по сети, которую я проверил в WireShark, там я вижу ответ в миллисекундах от всех клиентов только в тестовой программе. Это занимает много времени. Кто-нибудь может подсказать, какую ошибку я могу сделать? Ниже приведен код. Пожалуйста, объясните мне это. Я застрял в этом вопросе в течение последних 2 дней.

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

} `

Ответы [ 3 ]

1 голос
/ 05 сентября 2011

Я вижу две возможные причины вашей проблемы.

  1. Кажется, вы создали задержку в 100 мс для каждого ответа от каждого отвечающего клиента в вашем проекте.Первое, что вы делаете в методе BeginReceive, - это спите, независимо от того, есть данные или нет.Для каждого ответа вы (correclty) вызываете BeginReceive для регистрации вашего нового обратного вызова приема.Но поскольку в каждый момент времени регистрируется только один ReceiveCallback, обработка каждого ответа займет не менее 100 мс.Если вы получаете одновременно 30 входящих вызовов клиента, последний будет задержан на 3 секунды.

  2. В вашем ReceiveCallback вы вызываете свой метод OnFoundDevice.Это похоже на обратный вызов или обработчик событий.Любое время выполнения этого обратного вызова будет задерживать следующий обработанный ответ.Если обратный вызов занимает 1 минуту, следующий ответ будет отложен на 1 минуту (плюс 100 мс в вашем методе BeginReceive).

Предлагаемое решение: 1. Удалите задержку и условие из вашего BeginReceive,вот так.

public void BeginReceive()
{
     sock.BeginReceive(new AsyncCallback(ReceiveCallback), udpState);
}
  1. Просмотрите работу, выполненную OnFoundDevice.Если это занимает много времени, перенаправьте вызов в другой поток (например, выполнив QueueUserWorkItem в пуле потоков).

Если причина, по которой вы использовали sleep в своем BeginReceive, заключалась в том, чтобы найти критерии, когдаОстановите прослушивание данных, вместо этого вы можете запустить таймер для этого в своем методе Start и вызвать Close на вашем сокете по истечении заданного времени или когда вы не получили данные в течение установленного промежутка времени.

Надеюсь, это поможет вам.

1 голос
/ 17 мая 2011

Зачем вам нужно Thread.Sleep?

Это может вызвать задержки.

0 голосов
/ 27 сентября 2014

вы могли бы вместо этого использовать тайм-аут с блокирующим вызовом, как этот ... потому что, похоже, ваша программа не хочет выполнять какую-либо другую работу, пока она все равно ждет ... таким образом, если ответ приходит менее чем за 100 мс, вы не ' так долго ждать.

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.
...