简体   繁体   English

C# UdpSocket 发送后开始接收,几个包后停止接收

[英]C# UdpSocket starts receiving after send and stops receiving after a few packages

I'm trying to receive data via an UdpSocket from a multicast address.我正在尝试通过 UdpSocket 从多播地址接收数据。 The Socket doesn't receive data, before I sent data over the socket.在我通过套接字发送数据之前,套接字不接收数据。 After sending, i can receive a few packages, and then i have to send again, before I can receive more packages.发送后,我可以收到几个包裹,然后我必须再次发送,才能收到更多包裹。 Packages meanwhile sent from other hosts are lost.同时从其他主机发送的包丢失。 I think, it isn't a firewall issue like here: C# UDP Socket doesn't receive data until after data is sent because whireshark receives all packages.我认为,这不是像这里这样的防火墙问题: C# UDP Socket 直到发送数据后才接收数据,因为 whireshark 接收所有包。 Can somebody explain me this behavior?有人可以解释我这种行为吗?

class Program
{
    private static UdpClient _mdnsSocket;
    private static IPEndPoint _mdnsGroup;
    private static IPEndPoint _localEp;

    static void Main(string[] args)
    {
        var interfaces = NetworkInterface.GetAllNetworkInterfaces()
                                         .Where(i => i.OperationalStatus == OperationalStatus.Up)
                                         .ToArray();

        for (int i = 0; i < interfaces.Length; ++i)
        {
            var interf = interfaces[i];
            Console.WriteLine("{0}) Name: {1}", i, interf.Name);
        }
        Console.WriteLine();

        do
        {
            int i;
            Console.Write("Interface: ");
            var line = Console.ReadLine();
            if (int.TryParse(line, out i) && i < interfaces.Length)
            {
                var addr = interfaces[i].GetIPProperties()
                                        .UnicastAddresses.FirstOrDefault(a => a.Address.AddressFamily == AddressFamily.InterNetwork);
                if (addr != null)
                {
                    _localEp = new IPEndPoint(addr.Address, 5353);
                    Console.WriteLine("Choosen IP: {0}", _localEp);
                }
            }
        } while (_localEp == null);


        _mdnsGroup = new IPEndPoint(IPAddress.Parse("224.0.0.251"), 5353);
        _mdnsSocket = new UdpClient();
        _mdnsSocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        _mdnsSocket.ExclusiveAddressUse = false;
        _mdnsSocket.Client.Bind(_localEp);
        _mdnsSocket.JoinMulticastGroup(_mdnsGroup.Address, _localEp.Address);
        BeginReceive();

        Console.WriteLine("1 to switch to multicast mode (default)");
        Console.WriteLine("2 to switch to unicast mode");
        Console.WriteLine("s for sending a message");
        Console.WriteLine("ESC for exit");

        ConsoleKey key;
        IPEndPoint ip = _mdnsGroup;
        IPEndPoint unicastip = null;
        var mode = "multicast";

        do
        {
            Console.Write("1/2/s/ESC: ");
            key = Console.ReadKey().Key;
            Console.WriteLine();

            switch (key)
            {
                case ConsoleKey.D1:
                    ip = _mdnsGroup;
                    Console.WriteLine("Switched to multicast mode");
                    mode = "multicast";
                    break;

                case ConsoleKey.D2:
                    Console.Write("Enter new IP (leave empty to use {0}):", unicastip);
                    var input = Console.ReadLine();
                    if (string.IsNullOrEmpty(input))
                    {
                        if (unicastip == null)
                        {
                            Console.WriteLine("error: no last ip!");
                            break;
                        }
                        ip = unicastip;
                        Console.WriteLine("Switched to unicast mode");
                        mode = "unicast";
                    }
                    else
                    {
                        unicastip = new IPEndPoint(IPAddress.Parse(input), 5353);
                        ip = unicastip;
                        Console.WriteLine("Switched to unicast mode");
                        mode = "unicast";
                    }
                    break;

                case ConsoleKey.S:
                    var msg = string.Format("Hello from PC via {0}", mode);
                    var bytes = Encoding.ASCII.GetBytes(msg);

                    Console.WriteLine("Sending to {0}", ip);
                    _mdnsSocket.Send(bytes, bytes.Length, ip);
                    break;
            }
        } while (key != ConsoleKey.Escape);
        _mdnsSocket.Close();
    }

    private static void BeginReceive()
    {
        Console.WriteLine("BeginReceive");
        _mdnsSocket.BeginReceive(ReceiveCallback, _mdnsSocket);
    }

    private static void ReceiveCallback(IAsyncResult ar)
    {            
        try
        {
            var ep = new IPEndPoint(IPAddress.Any, _mdnsGroup.Port);
            var data = _mdnsSocket.EndReceive(ar, ref ep);

            var message = Encoding.ASCII.GetString(data);
            Console.WriteLine(message);
        }
        finally
        {
            BeginReceive();
        }
    }
}

After all it seems it was a firewall issue.毕竟它似乎是一个防火墙问题。 When I allow incoming UPD on Port 5353 explicitly, it's working (Why ever allowing all incoming UPD Traffic for the respective program doesn't work) .当我明确允许端口 5353 上的传入 UPD 时,它正在工作(为什么允许相应程序的所有传入 UPD 流量不起作用) I now explain the behavior described in the question with the so called hole punching mechanism.我现在用所谓的打孔机制解释问题中描述的行为。 Please correct me when I'm wrong.当我错了,请纠正我。

Same problem here, but firewall didn't fixed it.同样的问题在这里,但防火墙没有修复它。 I'm using Windows 10 PRO.我正在使用 Windows 10 PRO。

There is another undesired effect I have found: broadcasted messages are not being received, but straight IP messages are.我发现了另一个不良影响:没有收到广播消息,但收到了直接的 IP 消息。

The only workaround I've found was to add a timer that sends an empty byte array in broadcast every 10 seconds, so the communication is maintained well enough.我发现的唯一解决方法是添加一个计时器,该计时器每 10 秒在广播中发送一个空字节数组,因此通信保持得足够好。 The problem is that there are always useless messages transferred to the network, not so heavy, but far from optimal.问题是总是有无用的消息传输到网络,不是那么重,但远非最佳。

Closing the socket and starting again fixes also the problem, but it's slower, and forces the GC to run.关闭套接字并重新启动也可以解决问题,但速度较慢,并且会强制 GC 运行。

I'm using the same UDP class on Unity (Mono) and Visual Studio applications, but this "effect" only happens under Unity applications.我在 Unity (Mono) 和 Visual Studio 应用程序上使用相同的 UDP 类,但这种“效果”只发生在 Unity 应用程序下。 This only happens on IPV4 sockets, IPV6 sockets seems to never stop listening.这只发生在 IPV4 套接字上,IPV6 套接字似乎永远不会停止监听。

I'm sure this is some kind of "Stop using IPV4 broadcast" feature in new OS's, because Windows 7 works just fine.我确定这是新操作系统中的某种“停止使用 IPV4 广播”功能,因为 Windows 7 工作得很好。

Hope it helps.希望能帮助到你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM