2012-01-10 15 views
0

C#アプリケーションとC#アプリケーションを通信するためにUDPソケットを使用しています。C++とC#のソケットが正しく動作しない

C#→C++の方向ではすべてがうまくいっているようですが、それ以外の方法は私をナットとするものです。

コミュニケーションは機能しますが、C#アプリケーションでメッセージが送信されていても(3Dアプリケーション)、受信コードは10ミリ秒ごとに実行されています(2秒遅れなど) 。

これは非常に苦しい問題ですので、リアルタイムが必要です。これはパケット損失に関連すると思われますか?それでは、彼らは他の方向に迷子にならないのはなぜですか?

EDIT:データを同期するための

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(送信者)クラスの同期方法:

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 

    } 

Pr C#の終わりを受信するための完全なSocketManagerコードをoviding:

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ミリ秒を受け取る:私はあなたが最初のBeginReceiveをキックオフするとき

 _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; 
     } 
    } 
+1

あなたが間違っていることがありますが、問題が何に関連しているかを把握するための詳細やコードは提供していません。 –

+2

[Wireshark](http://www.wireshark.org/)のようなプログラムで未処理のパッケージをチェックしてください。それは実際の遅延がどこにあるのかを判断するのに役立ちます。 –

+1

C#側で受信するコードを提供できますか?また、パケットレベルで何が起きているかを証明するためにWiresharkトレースを実行することで利益を得ることができます。コードを提供するために編集された –

答えて

1

が表示されません。 (ああ、あなたの最初のタイマーティックからやっていますか?)データを受信する準備ができたらすぐにinitaitedする必要があります。次に、ReceiveCallbackは受け取ったデータを取得して何らかの並べ替えのキューに入れ、すぐにBeginReceiveを再度呼び出す必要があります。それ以外の場合は、前回の消費まで、次のデータフレームの到着を保留しています。最後に、スレッディングタイマーとUDPコールバックがそれぞれアプリケーションのメインスレッドの個別のスレッドで実行されるため、スレッドの問題を監視します。

コードがまったく機能する唯一の理由は、コールバックを受け取る前でも、MessageReceived = trueを事前に初期化しているためです。最初のティックが発生するとRecibeDatosの呼び出しはBegoolReceiveを呼び出します。これはそのboolがtrueに設定されているためです。

BeginReceiveは「ネットワークのデータがあるときに私に電話してください」と考えてください。タイマーを使用してネットワークをポーリングする必要はありません。 (アプリケーションが必要とする場合は、タイマーを介してそのデータを消費することを選択できますが、そのときはそのままにしておきます)。あなたがBeginReceiveを呼び出す必要があり

まず、開始時(またはなど、実行、有効化):ここで

はラフ手順です。データが到着したときに通知を受け取るようになりました。

第2に、コールバックが発生すると、EndReceiveを使用してデータバイトの読み取りを完了します。そのデータは、通常、バッファリングされるか、またはディスパッチされる。 BeginReceiveをコールバック内でもう一度呼び出すと、次のデータセットが利用可能になったときに再び通知を受けるようになります。これは一種の非同期ループになります。

質問はあなたが読んでいるデータをどうするかです。データをキューに配置し、タイマーで処理するためにこれらのデータフレームをキューから取り除くことを検討することもできます。あなたのティックの間にデータが何度も届くことに注意してください。

+0

私は、各タイマティックでRecibeDatos()関数を呼び出します。コールバック自体からBeginReceiveを呼び出す必要がありますか? –

+0

@kelmerもっと詳しく答えるために編集しました – tcarvin

+0

@kelmer何かを解明する必要がありますか? – tcarvin

関連する問題