2016-07-26 10 views
0

私はループの中でMQTT呼び出しを行い、各反復では、私が後に転送される値を使用できるように、出版された。しかし、問題は私がそれをどうやってやるか分からないことです。.NETクライアント - 次の要求に進む前にMQTT応答を待っています

私はあなたがそこにアイデアを持っていることを望むかもしれません。もし私がそれを正しく実装していないのであれば、あなたはこれを私に導くかもしれません。ありがとう。

はここに私のコードです:

// MyClientMgr 
class MyClientMgr{ 

    public long CurrentOutput { get; set; } 

    public void GetCurrentOutput(MyObjectParameters parameters, MqttClient client) 
    { 
     MyMessageObject msg = new MyMessageObject 
     { 
     Action = MyEnum.GetOutput, 
     Data = JsonConvert.SerializeObject(parameters) 
     } 
     mq_GetCurrentOutput(msg, client); 
    } 

    private void mq_GetCurrentOutput(MyMessageObject msg, MqttClient client) 
    { 
     string msgStr = JsonConvert.SerializeObject(msg); 
     client.Publish("getOutput", Encoding.UTF8.GetBytes(msgStr), 
MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false); 
     client.MqttMsgPublishReceived += (sender, e) =>{ 
      MyObjectOutput output = JsonConvert.DeserializeObject<MyObjectOutput>(Encoding.UTF8.GetString(e.Message)); 
      CurrentOutput = output; 
     }; 
    } 

} 

// MyServerMgr 
class MyServerMgr 
{ 
    public void InitSubscriptions() 
    { 
     mq_GetOutput(); 
    } 

    private void mq_GetOutput() 
    { 
     MqttClient clientSubscribe = new MqttClient(host); 
     string clientId = Guid.NewGuid().ToString(); 
     clientSubscribe.Connect(clientId); 
     clientSubscribe.Subscribe(new string[] { "getOutput" }, new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE }); 

     MqttClient clientPublish = new MqttClient(host); 
     string clientIdPub = Guid.NewGuid().ToString(); 
     clientPublish.Connect(clientIdPub); 
     clientSubscribe.MqttMsgPublishReceived += (sender, e) => { 
      MyMessageObj msg = JsonConvert.DeserializeObject<MyMessageObj>(Encoding.UTF8.GetString(e.Message)); 

      var output = msg.Output; 
      clientPublish.Publish("getOutput", Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(output)), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false); 
     } 
    } 
} 

// MyCallerClass 
class MyCallerClass 
{ 
    var host = "test.mqtt.org"; 
    var myServer = new MyServerMgr(host); 
    var myClient = new MyClientMgr(); 

    myServer.InitSubscriptions(); 
    MqttClient client = new MqttClient(host); 
    for(int i = 0; i < 10; i++) 
    { 
     long output = 0; 

     MyObjectParameters parameters = {}; 
     myClient.GetCurrentOutput(parameters, client) // here I call the method from my client manager 
     // to publish the getting of the output and assigned 
     // below for use, but the problem is the value doesn't 
     // being passed to the output variable because it is not 
     // yet returned by the server. 

     // Is there a way I could wait the process to 
     // get the response before assigning the output? 

     output = myClient.CurrentOutput; // output here will always be null 
    // because the response is not yet forwarded by the server 

    } 
} 

私は出力を取得するため公開MQTTを呼び出すために私の呼び出し側のクラスでループを持っていますが、私はそれが割り当てられていた前の出力を取得する方法が分からない、私が欲しいです最初に応答を待ってから次へ進む。

私はすでに内部で次のようにwhileループをやってみました:

while(output == 0) 
{ 
    output = myClient.CurrentOutput; 
} 

はい、私はここに出力を得ることができますが、それは多くのプロセスが遅くなります。そして時々それは失敗するでしょう。

私を助けてください。ありがとう。

答えて

0

非同期プロトコル(MQTT)で同期通信を実行しようとしているようです。

これは、メッセージを送信してから応答を待つことを意味します。これは、プロトコル・レベルでのメッセージへの応答の概念がないためMQTTが機能する方法ではありません。

私はC#に精通していないので、解決策の抽象的な説明をします。

公開スレッドであるwait/pulse(Monitorクラスを参照)を使用して、公開後にこのブロックを作成し、レスポンスを受信したときにメッセージハンドラコールパルスを持たせることをお勧めします。

応答に元の要求を識別するための待機が含まれていない場合は、どの要求が進行中であるかを記録するために状態マシン変数も必要です。

何らかの理由で他端が応答しない場合に備えて、タイムアウトを待つことをお勧めします。

+0

C#では、 'Task'と' TaskCompletionSource'を使うのはもっと慣用的/近代的です。 – canton7

0

WaitOne()メソッドとSet()メソッドを持つAutoResetEventクラスを使用できます。パブリッシュ後にWaitOne()を使用すると、メッセージがパブリッシュされるまで待機し、client_MqttMsgPublishReceivedイベントの下でSet()を使用すると、サブスクライバが購読したメッセージを受信したときの待機が解放されます。

+0

client_MqttMsgPublishReceivedは、サブスクライバがメッセージを受信したことを示すものではなく、ブローカがメッセージを受信したことを示します。 MQTTにエンド・ツー・エンド配信通知はありません – hardillb

関連する問題