Не могу присоединиться к многоадресной группе С#

В моем проекте мне нужно получать видео через UDP. Источник имеет IP-адрес 224.0.0.21, приемник имеет IP-адрес 169.254.170.141. Я получаю видео через порт 3956 (это достоверная информация от Wireshark). Я использую SharpPcap для получения UDP-трафика, но у него нет методов для присоединения к многоадресной рассылке. Я пробую этот код из MSDN, но он не работает.

        IPAddress multicastaddress = IPAddress.Parse("224.0.0.21");
        IPEndPoint remoteep = new IPEndPoint(IPAddress.Any, 3956);
        m_ClientTarget.JoinMulticastGroup(multicastaddress, localAddr);

На моем ПК есть несколько сетевых адаптеров, но я использую IP-адрес устройства, которое подключено к источнику видео. Источник и приемник подключены напрямую. Когда я запускаю мониторинг трафика в wireshark, моя программа также получает пакет, но без wireshack она не может этого сделать. Мой код:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SharpPcap;
using SharpPcap.LibPcap;
using SharpPcap.AirPcap;
using SharpPcap.WinPcap;
using System.IO;
using System.Net.Sockets;
using System.Net;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading;

namespace GVSPCapture
{
    public partial class Form1 : Form
    {

        static int frameCounter = 0;
        static byte[] pixels = new byte[1920 * 1080 * 3];
        static IPAddress fpgaAddr = IPAddress.Parse("224.0.0.21");
        static IPAddress localAddr = IPAddress.Parse("169.254.170.141");
        static MulticastOption mcastOption = new MulticastOption(fpgaAddr, localAddr);
        private static UdpClient m_ClientTarget = new UdpClient(3956);
        private static IPAddress m_GrpAddr;
        const int GroupPort = 3956;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            findDevices();
        }

        public void findDevices()
        {
            string ver = SharpPcap.Version.VersionString;

            var devices = CaptureDeviceList.Instance;

            foreach (var dev in devices)
            {
                lbxDevices.Items.Add(dev.Name + dev.Description);
            }

        }

        private void JoinVideoMulticast()
        {

            IPAddress multicastaddress = IPAddress.Parse("224.0.0.21");
            IPEndPoint remoteep = new IPEndPoint(IPAddress.Any, 3956);
            m_ClientTarget.JoinMulticastGroup(multicastaddress, IPAddress.Parse("169.254.170.141"));

            while (true)
            { }

        }

        private void startCapture(ICaptureDevice dev)
        {
            if (!dev.Started)
            {
                dev.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival);
                int readTimeoutMilliseconds = 1000;
                if (dev is AirPcapDevice)
                {
                    // NOTE: AirPcap devices cannot disable local capture
                    var airPcap = dev as AirPcapDevice;
                    airPcap.Open(SharpPcap.WinPcap.OpenFlags.DataTransferUdp, readTimeoutMilliseconds);
                }
                else if (dev is WinPcapDevice)
                {
                    var winPcap = dev as WinPcapDevice;

                    winPcap.Open(SharpPcap.WinPcap.OpenFlags.DataTransferUdp | SharpPcap.WinPcap.OpenFlags.NoCaptureLocal, readTimeoutMilliseconds);
                }
                else if (dev is LibPcapLiveDevice)
                {
                    var livePcapDevice = dev as LibPcapLiveDevice;
                    livePcapDevice.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
                }
                else
                {
                    throw new System.InvalidOperationException("unknown device type of " + dev.GetType().ToString());
                }

                dev.StartCapture();

                Thread recvThread = new Thread(JoinVideoMulticast);
                recvThread.Start();

            }
        }

        delegate void SetTextCallback(string text);

        private void SetText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.tbxCnt.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.tbxCnt.Text = text;
            }
        }

        private void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            var time = e.Packet.Timeval.Date;
            var len = e.Packet.Data.Length;
            if (len == 572)
            {
                var tmp = e.Packet.Data;
                int packet_id = tmp[47] << 16 | tmp[48] << 8 | tmp[49];
                int startPos = (packet_id - 1) * 522;
                for (int i = 50; i < tmp.Length; i+=3)
                {
                    pixels[startPos + i + 0 - 50] = tmp[i];
                    pixels[startPos + i + 1 - 50] = tmp[i];
                    pixels[startPos + i + 2 - 50] = tmp[i];
                }
            }
            if (len == 60)
            {
                var im = CopyDataToBitmap(pixels);
                pictbFrame.Image = im;
                frameCounter += 1;
                SetText(frameCounter.ToString());
            }
        }

        public Bitmap CopyDataToBitmap(byte[] data)
        {
            GCHandle pinned = GCHandle.Alloc(data, GCHandleType.Pinned);
            IntPtr ptr = pinned.AddrOfPinnedObject();
            BitmapData dt = new BitmapData();
            dt.Scan0 = ptr;
            dt.Stride = 5760;
            dt.Width = 1920;
            dt.Height = 1080;
            dt.PixelFormat = PixelFormat.Format24bppRgb;
            Bitmap btm = new Bitmap(1920, 1080, 5760, PixelFormat.Format24bppRgb, dt.Scan0);
            return btm;
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            int devNum = lbxDevices.SelectedIndex;
            if (devNum > 0)
            {
                var device = CaptureDeviceList.Instance[devNum];
                startCapture(device);
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            int devNum = lbxDevices.SelectedIndex;
            if (devNum > 0)
            {
                var device = CaptureDeviceList.Instance[devNum];
                if (device.Started)
                {
                    device.StopCapture();
                    device.Close();
                }
            }
            m_ClientTarget.DropMulticastGroup(fpgaAddr);
        }
    }
}

person Андрей Кущенко    schedule 24.08.2017    source источник
comment
Одна из проблем заключается в том, что это многоадресный адрес, зарезервированный для функций маршрутизатора, и вам не следует пытаться присоединиться к нему на ПК в первую очередь.   -  person Ron Maupin    schedule 24.08.2017
comment
@RonMaupin Что плохого в присоединении к многоадресному адресу?   -  person L.B    schedule 24.08.2017
comment
Плохо, когда мультикаст-группа зарезервирована для другой цели. Эта многоадресная группа никогда не должна использоваться для видео. Существует блок многоадресных адресов (239.0.0.0-239.255.255.255 Organization-Local Scope), зарезервированный для этого типа вещей. Это похоже на попытку использовать IP-адреса, принадлежащие Google, в своих целях. IANA поддерживает Реестр многоадресного адресного пространства IPv4< /i> так же, как они поддерживают назначение одноадресных адресов.   -  person Ron Maupin    schedule 24.08.2017
comment
Кстати, многоадресные адреса — это адреса назначения, а не адреса источника.   -  person Ron Maupin    schedule 24.08.2017
comment
@RonMaupin Что плохого в присоединении к многоадресному адресу? ОП не говорит, что отправляет данные на этот адрес. Источником видео может быть все, что пользователь не может контролировать.   -  person L.B    schedule 24.08.2017
comment
Но эта многоадресная группа зарезервирована для маршрутизаторов. ПК, не являющиеся маршрутизаторами, не имеют права присоединяться к группе многоадресной рассылки. Похоже, проект имеет серьезные недостатки в том, что групповой адрес многоадресной рассылки используется в качестве источника, а не пункта назначения.   -  person Ron Maupin    schedule 24.08.2017
comment
PCs that are not routers have no business joining the multicast group Может быть, это именно то, что я хочу сделать. Так что не вижу никакого вреда в присоединении к какой-либо многоадресной группе. Единственная проблема заключается в отправке данных в эту группу, если они зарезервированы для другого использования (кстати: просто для информации, я использую многоадресные рассылки для SSDP и SAP, так что я не новичок в этой теме)   -  person L.B    schedule 24.08.2017
comment
Давайте продолжим это обсуждение в чате.   -  person Ron Maupin    schedule 25.08.2017
comment
Может быть, это плохой адрес, но я могу получать видео, если я начну отслеживать трафик с помощью Wireshark.   -  person Андрей Кущенко    schedule 25.08.2017


Ответы (2)


Не видя вашего кода (я предполагаю, что это нечто большее, чем фрагмент, который вы показываете), трудно вам помочь. Базовая настройка для клиента, получающего многоадресные дейтаграммы, будет примерно такой, как этот непроверенный фрагмент:

UdpClient mClient = new UdpClient(3956, AddressFamily.InterNetwork);
IPAdress groupAddress = IPAddress.Parse("224.0.0.21);
mClient.JoinMulticastGroup(groupAddress);

После этого вы получаете с помощью mClient.Receive()...

Может быть, это помогает? Или документация на MSDN (https://msdn.microsoft.com/en-us/library/ekd1t784(v=vs.110).aspx).

C.

person C. Gonzalez    schedule 24.08.2017

Я тестировал код с помощью ffmpeg.

ffmpeg.exe -i aa.mp4 -f mpeg udp://224.0.0.21:3956

int PORT = 3956;
string MULTICAST_IP = "224.0.0.21";


UdpClient udpClient = new UdpClient(PORT);
udpClient.JoinMulticastGroup(IPAddress.Parse(MULTICAST_IP));

var from = new IPEndPoint(0, 0);
var recvBuffer = udpClient.Receive(ref from);
person L.B    schedule 24.08.2017