【问题标题】:UDPClient Async BeginReceive is very slowUDPClient Async BeginReceive 很慢
【发布时间】:2011-05-17 07:38:38
【问题描述】:

我正在使用 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();
    }

}`

【问题讨论】:

  • 为什么需要这个?他们没有发送/接收缓冲区刷新命令吗? //每次我们开始发现时都需要创建新对象,因为 //每次 udp 缓冲区都需要刷新并重新启动 sock = new UdpClient();
  • 我知道这是一个旧线程 - 但你找到修复了吗?我现在有这个问题。

标签: c# .net multicast udpclient


【解决方案1】:

为什么需要Thread.Sleep

这可能会导致延迟。

【讨论】:

  • 应该是评论。请删除。
  • @the_drow - 为什么?桑迪普问为什么它很慢。这可能是答案。如果有一个大的分片数据包,并且每个分片的接收都有延迟。
  • @AlexAza:你确定这是它慢的唯一原因吗?我不是。事实上,这可能是有道理的。你没有提出任何解决问题的方法。为了找出他使用Thread.Sleep() 的原因,您应该使用评论询问他。你无法回答你自己不知道的事情。
  • @alex:我不会 -1 你 - 但是为什么 - 他说他有 2-3 分钟的延迟 - 显然使用 100 毫秒睡眠不会累积到 2-3 分钟,除非他有几个将响应请求的数千个对等点。
  • Thread.Sleep() 需要在接收呼叫之间提供一些间隙,没有它,我不会收到任何需要延迟的数据包。但我认为这不是问题,我会延迟 2-3 分钟
【解决方案2】:

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

  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在设定的时间跨度内收到数据。

希望对你有所帮助。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2013-08-21
      • 2012-12-27
      • 1970-01-01
      • 1970-01-01
      • 2017-09-12
      • 2019-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多