我正在使用UDP套接字与C#应用程序通信C ++应用程序。

在C#-> C ++方向上,一切似乎都工作正常,但是反过来又使我发疯。

通讯确实可以,但是C#应用程序中的消息变得很晚(例如2秒钟的延迟),即使它们每帧都发送一次(这是3D应用程序),并且接收代码每10毫秒执行一次。

我需要实时,所以这是一个非常痛苦的问题。您是否认为这可能与丢包有关?那他们为什么不迷失在另一个方向上呢?

编辑:

用于同步数据的C#应用​​代码:

    public void RecibeDatos()
    {
       if (MessageReceived && U != null && S != null)
       {
          MessageReceived = false;
          //Console.WriteLine("listening for messages");
          U.BeginReceive(ReceiveCallback, S);
       }
    }

    public void ReceiveCallback(IAsyncResult ar)
    {
        UdpClient u = ((UdpState)(ar.AsyncState)).U;
        IPEndPoint e = ((UdpState)(ar.AsyncState)).E;

        receivedBytes = u.EndReceive(ar, ref e);
        //int currentProtocol = (int) numero;
        //ResetSignal = reset > 0;

        //Console.WriteLine("Received: " + currentProtocol);
        MessageReceived = true;
    }


用于发送数据的C ++代码:

    float indiceFloat[1];
    indiceFloat[0] = indice_protocolo_actual;
    sender->setBuffer((void *)indiceFloat, sizeof(indiceFloat));
    sender->sync();


J_Enviar(发送者)类上的sync方法:

    void J_Enviar::sync( void )
    {
        if(!_initialized) init();

        if( _buffer == 0L )
        {
            fprintf( stderr, "Broadcaster::sync() - No buffer\n" );
            return;
        }

    #if defined (WIN32) && !defined(__CYGWIN__)
        unsigned int size = sizeof( SOCKADDR_IN );
        sendto( _so, (const char *)_buffer, _buffer_size, 0, (struct sockaddr *)&saddr, size );
        int err = WSAGetLastError ();
        if (err!=0)
            fprintf( stderr, "Broadcaster::sync() - error %d\n",err );
    #else
        unsigned int size = sizeof( struct sockaddr_in );
        sendto( _so, (const void *)_buffer, _buffer_size, 0, (struct sockaddr *)&saddr, size );
    #endif

    }


提供完整的SocketManager代码以接收C#端:

using System;
using System.Net;
using System.Net.Sockets;

namespace WpfApplication1
{
public class SocketManager
{
    private static SocketManager _instance = null;
    static readonly object Padlock = new object();

    private IPEndPoint E;
    private UdpClient U;
    private UdpState S;

    private byte[] receivedBytes;


    public static bool MessageReceived = true;

    private SocketManager()
    {

    }

    public byte[] ReceivedBytes
    {
        get { return receivedBytes; }
    }

    public static SocketManager Instance
    {
        get
        {
            lock(Padlock)
            {
                return _instance ?? (_instance = new SocketManager());
            }
        }
    }

    public void CreateReceivingSocket(IPAddress a, int puerto)
    {

        if(E==null || (E.Address != a && E.Port != puerto))
        {
            E = new IPEndPoint(a, puerto);
            U = new UdpClient(puerto);
            S = new UdpState { E = E, U = U };
        }

    }


    public void ReceiveCallback(IAsyncResult ar)
    {
        UdpClient u = ((UdpState)(ar.AsyncState)).U;
        IPEndPoint e = ((UdpState)(ar.AsyncState)).E;

        receivedBytes = u.EndReceive(ar, ref e);
        //int currentProtocol = (int) numero;
        //ResetSignal = reset > 0;

        //Console.WriteLine("Received: " + currentProtocol);
        MessageReceived = true;
    }

    public void RecibeDatos()
    {
        if (MessageReceived && U != null && S != null)
        {
            MessageReceived = false;
            //Console.WriteLine("listening for messages");
            U.BeginReceive(ReceiveCallback, S);
        }
    }

    public void CloseConnection()
    {
        if (E != null)
        {
            E.Port = 5502;
            E = null;
        }
        if (U != null)
            U.Close();

    }
}

public class UdpState
{
    public IPEndPoint E;
    public UdpClient U;
}
}


这是我的dispatchertimerclick,它使程序每10毫秒接收一次:

        _dispatcherTimer.Tick += DispatcherTimerTick;
        _dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1);
        _dispatcherTimer.Start();

    private void DispatcherTimerTick(object sender, EventArgs e)
    {
        _exp1Class.sendData();
        _sm.RecibeDatos();
        byte[] recibidos = _sm.ReceivedBytes;
        if (recibidos != null)
        {
            float numero = BitConverter.ToSingle(recibidos, 0);

            _exp1Class.CurrentProtocol = (int) numero;
        }
    }

最佳答案

当您启动第一个BeginReceive时,我看不到。 (啊,这是我第一次计时滴答完成的吗?)一旦准备好接收数据,应该立即启动它。其次,您的ReceiveCallback应该获取接收到的数据并将其放入某种队列中,然后立即再次调用BeginReceive。否则,您将阻止下一个数据帧的到达,直到前一个数据帧被消耗为止。最后,注意线程问题,因为线程计时器和UDP回调将分别在与应用程序主线程分开的线程上运行。

代码根本无法工作的唯一原因是,即使在收到任何回调之前,您都已预先初始化了MessageReceived = true。第一次滴答发生时,对RecibeDatos的调用将调用BeginReceive,因为该布尔值已设置为true。

想想BeginReceive是说“当您从网络中获得一些数据时回叫我”。您无需使用计时器来轮询网络。 (如果您的应用程序需要,您可以选择通过计时器使用该数据,但暂时不要使用它)。

大致步骤如下:

首先,启动(或启用,运行等)后,应调用BeginReceive。现在,当数据到达时,您将收到通知。

其次,发生回调时,您可以使用EndReceive完成对数据字节的读取。该数据通常将被缓冲或以其他方式调度。然后,您应该再次(在回调函数中)调用BeginReceive,以便在下一组数据可用时,您将再次收到通知。它成为一种异步循环。

问题是如何处理您正在读取的数据。您可能考虑将数据放入队列中,然后让Timer将这些数据帧从队列中弹出进行处理。请注意,数据在两次“滴答”之间可以多次到达。

08-27 14:19