UDPClient Async BeginReceive 非常慢

发布于 2024-11-08 05:27:36 字数 3294 浏览 5 评论 0原文

我正在使用 UDPClient 发送多播请求并接收来自网络上各个客户端的响应。我能够发送请求并获得响应,但我得到的响应非常慢。需要 2-3 分钟才能得到所有客户的回复。在我检查 WireShark 的网络上发送请求时,我仅在测试程序中看到来自所有客户端的毫秒响应。这需要很多时间。谁能指导我可能会犯什么错误?以下是代码。请指导我。过去两天我一直被这个问题困扰。

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

}`

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

}`

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

紫南 2024-11-15 05:27:36

为什么需要Thread.Sleep?

这可能会导致延误。

Why do you need Thread.Sleep?

It might cause the delays.

何时共饮酒 2024-11-15 05:27:36

我发现您的问题有两个可能的原因。

  1. 看来您在设计中为每个响应客户端的每个响应内置了 100 毫秒的延迟。在 BeginReceive 方法中,您要做的第一件事就是休眠,无论是否有数据。对于每个响应,您(正确地)调用 BeginReceive 来注册新的接收回调。但由于一次只注册一个 ReceiveCallback,因此处理每个响应至少需要 100 毫秒。如果您同时收到 30 个传入客户端调用,则最后一个客户端调用将延迟 3 秒。

  2. 在 ReceiveCallback 中,您调用方法 OnFoundDevice。这看起来像回调或事件处理程序。此回调花费的任何执行时间都会延迟下一个处理的答案。如果回调需要 1 分钟,则下一个响应将延迟 1 分钟(在 BeginReceive 方法中加上 100 毫秒)。

建议的解决方案:
1. 从 BeginReceive 中删除延迟和条件,如下所示。

public void BeginReceive()
{
     sock.BeginReceive(new AsyncCallback(ReceiveCallback), udpState);
}
  1. 回顾一下 OnFoundDevice 所做的工作。如果很耗时,请将调用编组到另一个线程(例如,通过在线程池上执行 QueueUserWorkItem)。

如果您在 BeginReceive 中使用 sleep 的原因是为了找到何时停止侦听数据的标准,您可以在 Start 方法中为此启动一个计时器,并在预定时间后或未接收到数据时在套接字上调用 Close在设定的时间范围内。

我希望这对你有帮助。

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.

凉城 2024-11-15 05:27:36

您可以使用像这样的阻塞调用超时...因为看起来您的程序在等待时不想做任何其他工作..这样,如果响应时间少于 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.

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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文