C#: Socket - Multicast, No Data received, BeginReceive/BeginReceiveFrom Callback is not called

512 Views Asked by At

I'm actually at a loss, I have this problem for some time now. I searched Stackoverflow and couldn't find a solution.

The Problem is as follows: I dont receive any data and the Callback from BeginReceive or BeginReceiveFrom, from the Socket (multicast) is never called, and the data is never processed and I don't seem to be able to find the reason. I can't see the forest for the trees :(

If I debug the application step by step, I sometimes receive data and sometimes not. If I debug without breakpoints and without "step by step" it never works.

When I sniff the multicast address with wireshark I can see the packages arriving, and I know that packages are sent by the server every 500ms.

Here is the Code for the UnitTest Program and the Socket Initialization, Connection and Receiving.

Maybe someone can help me find the bug or point me into the right direction...

This is how I initialize the socket:

public void Initialize()
{
    IPAddress multicastIP = IPAddress.Parse(mcastConfig.RemoteIPAddress);
    IPAddress localIP = IPAddress.Parse(mcastConfig.LocalIPAddress);

    _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

    _socket.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.NoDelay, 1);
    _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

    IPEndPoint localEP = new IPEndPoint(localIP, mcastConfig.RemotePort);

    _socket.Bind(localEP);

    _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 5);

    _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)localIP.Address);

    multicastEndPoint = new IPEndPoint(multicastIP, mcastConfig.RemotePort);

    MulticastOption mcastOption = new MulticastOption(multicastIP, localIP);

    _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, mcastOption);

    Connect();
}

The AsyncConnect works fine it looks like this:

public void Connect()
{

    if (!Connected)
    {
        _socket.BeginConnect(multicastEndPoint, new AsyncCallback(ConnectCallback), _socket);

        connectDone.WaitOne();
        Connected = true;
    }
}

private static void ConnectCallback(IAsyncResult ar)
{
    try
    {
        Socket client = (Socket)ar.AsyncState;

        client.EndConnect(ar);

        connectDone.Set();
    }
    catch (Exception e)
    {
        _log.Error("### Error with the Connection: {0}", e.ToString());
    }
}

The Problem starts with the BeginReceive, it is called once but then nothing happens and the callback itself is only called when the socket is closed (as it should be, already read that here):

public void Receive()
{

    byte[] data = new byte[_buffer.Length];

    if (!Connected)
    {
        Connect();
    }

    try
    {
        mcastEP = multicastEndPoint;

        IPAddress localIP = IPAddress.Parse(mcastConfig.LocalIPAddress);
        EndPoint localEP = new IPEndPoint(localIP, mcastConfig.RemotePort);

        _socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), _socket);
        //_socket.BeginReceiveFrom(_buffer, 0, _buffer.Length, SocketFlags.None, ref localEP, new AsyncCallback(ReceiveCallback), _socket);

        Array.Copy(_buffer, data, _buffer.Length);

        pDUHelper.ProcessData(data); //This processes the data and sends an event if the data was correct received
    }
    catch (SocketException se)
    {
        _log.Error("### SocketException ErrorCode: {0}, see: https://support.microsoft.com/en-us/help/819124/windows-sockets-error-codes-values-and-meanings", se.ErrorCode.ToString());
    }
    catch(Exception e)
    {
        _log.Error(e);
    }
}

private void ReceiveCallback(IAsyncResult ar)
{
    Socket socket = ar.AsyncState as Socket;
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 0);
    EndPoint ep = ipep;

    try
    {
        int reicevedBytes = _socket.EndReceive(ar);
        //int reicevedBytes = _socket.EndReceiveFrom(ar, ref ep);

        ipep = ep as IPEndPoint;

        if(reicevedBytes > 0)
        {
            byte[] data = new byte[reicevedBytes];
            Array.Copy(_buffer, data, reicevedBytes);

            pDUHelper.ProcessData(data); //This processes the data and sends an event if the data was correct received

            receiveDone.Set();
        }
    }
    catch (ObjectDisposedException ode)
    {
        _log.Error(ode);
    }
    catch (SocketException se)
    {
        _log.Error(se);
    }
    catch(Exception e)
    {
        _log.Error(e);
    }
    finally
    {
        _socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), _socket);
        //_socket.BeginReceiveFrom(_buffer, 0, _buffer.Length, SocketFlags.None, ref ep, new AsyncCallback(ReceiveCallback), _socket);
    }
}

My Unit Test Program

class Program
{
    static ConcurrentQueue<CallListLine> _workerQueue = new ConcurrentQueue();


    static void Main(string[] args)
    {
        Console.WriteLine("Create Configuration");
        ConfigurationHelper.Configuration.LoadOrCreateConfiguration();
        _workerQueue.AddProvider("Testsystem");

        MulticastConfiguration mc = new MulticastConfiguration
        {
            LocalIPAddress = "192.168.0.15",
            LocalPort = 0,
            RemoteIPAddress = "233.233.233.233",
            RemotePort = 43238,
            MaxSegmentSize = 200,
            ReceiveBufferSize = 8192,
            SocketBufferSize = 64000,
            IsConfigured = true
        };

        Console.WriteLine(mc);

        MulticastReceiver mr = new MulticastReceiver(mc);

        Console.WriteLine("Init");
        mr.Initialize();

        Console.WriteLine("Creating PDU Helper");

        mr.NewCallListReady += CallListReadyToProcess;

        mr.Receive();

        int counter = 0;
        while (true)
        {
            Console.WriteLine("Messages for Testsystem: {0}, Counter: {1}", _workerQueue.Count, counter);
            Thread.Sleep(1000);
            if (counter == 20)
                break;
            counter++;
        }

        Console.WriteLine("Press any Key to End!");
        Console.ReadLine();
        mr.Stop();
    }

    static void CallListReadyToProcess(object sender, EventArgs e)
    {
        MTPEventArgs test = e as MTPEventArgs;

        Console.WriteLine("Received new Line: {0}", test.CallList);

        CallListLine tempLine = new CallListLine
        {
            Provider = "Testsystem",
            Data = test.CallList,
            TimeStamp = DateTimeOffset.Now
        };
        _workerQueue.Enqueue(tempLine);
    }
}
0

There are 0 best solutions below