2016-08-30 3 views
2

まず、私は統一を使用しています。 .NET 3.5に悩まされています。私は現在、Socketオブジェクトの非同期メソッド(E.G. BeginReceiveBeginAcceptBeginReceiveFromなど)を使用するサーバープログラムに取り組んでいます。サーバーがクライアントからパケットを受信すると、このパケットはワーカースレッドで受信されます。今私はワーカースレッド上にいくつかのデータが残っているので、私が指定した関数を使ってこのデータをメインスレッドに処理させたい。そして、私はそれをこのように使用することになりFIFOプログラミングされたメインスレッドディスパッチャ?

using System; 
using System.Threading; 
using System.Collections; 
using System.Collections.Generic; 

public class MyDispatcherClass 
{ 
    public delegate void MyDel(); 
    private readonly Queue<MyDel> commands = new Queue<MyDel>(); 
    Object lockObj = new object(); 

    public void Add(MyDel dc) 
    { 
     lock (lockObj) 
     { 
      commands.Enqueue (dc); 
     } 
    } 

    public void Invoke() 
    { 
     lock (lockObj) 
     { 
      while (commands.Count > 0) 
      { 
       commands.Dequeue().Invoke(); 
      } 
     } 
    } 
} 

::私はことを実現し、いくつかの研究の後

// As a global variable: 
MyDispatcherClass SomeDispatcher = new MyDispatcherClass(); 

//The function that I want to call: 
public void MyFunction (byte[] data) 
{ 
    // Do some stuff on the main thread 
} 

//When I receive a message on a worker thread I do that: 
SomeDispatcher.Add (()=> MyFunction (byte[] data)); //Asuume that "data" is the message I received from a client 

//Each frame on the main thread I call: 
SomeDispatcher.Invoke(); 

を、私はlock文が%100 FIFOの実装を保証するものではないことがわかりました。これは私の望むものではありませんが、時にはこれがサーバーの故障の原因になることがあります。データがクライアントから受け取ったのと同じ順序で処理されることを保証する%100という同じ結果を達成したいと思います。どうすればそれを達成できますか?

+0

あなたは1人のクライアントで1人のクライアントからすべてのデータを取得しますか?もしそうなら、ディスパッチャーに 'AddRange'メソッドを追加することができます。ディスパッチャーは、引数として' IEnumerable 'をとり、それらを同じロック本体に追加します。 – ArgusMagnus

+1

私は以前これを調べました。私は各クライアント1からデータを受け取り、SomeDispatcher.Addを呼び出すスレッドは、各クライアント(これはMicrosoftが実装した実装です)でも常に変化している可能性があります。 – None

答えて

1

スレッドは必要な順序で実行されるため、注文を強制的にキューに入れることはできません。しかし、最終的に処理するものより多くのデータをキューに入れることができます。

送信されるデータにDateTime(または指定された順序のintだけ)を追加すると、データを取得する際にキューをソートできます(0.5未満のデータを取得しない可能性もあります)他のスレッドがデータを書き込む時間を与えるために秒単位で指定します)。

通常、クライアントとサーバの関係を扱う場合、各スレッドは1つのクライアントを表します。したがって、コマンドがスレッド内のFIFOであるので心配する必要はありません。 2つの異なるクライアントがメッセージを送信しているときではないかもしれません)。

同じクライアントでソケットを閉じてもう一度開きますか?異なるスレッドを使用する可能性があります。あなたが特定の注文を必要とし、お互いにすぐに物事を送信している場合は、ソケットを開いたままにする方が良いかもしれません。

+1

"通常、クライアントとサーバーの関係を扱う場合、各スレッドは1つのクライアントを表します"、間違っています。これはサーバーの安価な実装です。 C#で 'Socket'sの非同期関数を使用してもそれは行いません。 「あなたは同じクライアント上のソケットを閉じて再オープンしますか?」もちろん、私はそうではありません。 – None

+0

非同期関数は、必要な順番ではなく実行できるように設計されています。同期バージョンに切り替えるか、送信するデータの一部としてクライアント側にDateTime /処理オーダーカウンターを追加できますか? –

+1

「同期バージョンに切り替えることはできますか?」:パフォーマンスに大きな影響を与え、スケーラビリティのないサーバーになります。 「送信しているデータの一部として、クライアント側のDateTime /処理オーダーカウンターを追加できますか?」:残念ながら、これはゲーム用のAPIです。このため、私は送信データ量を可能であれば(私はソケットプログラミングのすべての問題を解決するために1バイトのUDPヘッダを使用しています、すべての接続を管理し、各クライアントに一意のIDを割り当て、接続ハンドシェイクを持っています)挫折! – None

関連する問題