IPCにZeroMQを使い始め、単純なエコークライアント/サーバーを作成しました。1つのことに驚いています。これがC++コードです(zmq.hpp
とzmq_addon.hpp
を使用)。
サーバ:
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REP);
socket.bind("ipc:///tmp/machine-1");
while (1) {
zmq::multipart_t m;
m.recv(socket);
int i = m.poptyp<int>();
i++;
m.addtyp<int>(i);
m.send(socket);
}
クライアント:
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REQ);
socket.connect("ipc:///tmp/machine-1");
int i = 0;
while (1) {
int save = i;
zmq::multipart_t m;
m.addtyp<int>(i);
m.send(socket);
m.recv(socket);
i = m.poptyp<int>();
if (i != (save + 1))
break;
if ((i % 100000) == 0)
std::cerr << "i : " << i<< "\n";
}
期待通りに動作します。クライアントはint
を送信し、サーバーはプラス1を送信して送り返します。
今、私が理解していない魔法:クライアントを複数回並行して実行でき、クライアントごとに正しく機能し続けることに気づきました。
save+1
とi
を比較するチェックは常にOKです。
ZMQはサーバー側の同時実行の問題をどのように処理しますか?どのクライアントに応答を返送する必要があるかをどのように知るのですか?
SOにこの質問がありますが、私の質問には答えられません: ipc://および同時実行性のZeroMQ REQ/REP
Zeromqのドキュメントによると、サーバーでREP.recv()を呼び出すと、キューに入れられたREQ(クライアント)ソケットからメッセージが返されます。複数のクライアントが接続されている場合は、均等化キューポリシーを使用して1つを選択します。 REP.send()を呼び出して応答すると、REPソケットは常に対応するREQクライアントに応答を送信します。
これが「魔法」です。REPソケットが正しいクライアントに応答を送信します。クライアントが切断されている場合は、応答メッセージをドロップするだけです。
docs は私の説明よりも明確かもしれません:
ZMQ_REP:タイプZMQ_REPのソケットは、クライアントとの間で要求を受信し、クライアントに応答を送信するためにサービスによって使用されます。このソケットタイプでは、zmq_recv(request)呼び出しとそれに続くzmq_send(reply)呼び出しの交互のシーケンスのみが許可されます。受信した各リクエストはすべてのクライアントから均等化キューイングされ、送信された各応答は最後のリクエストを発行したクライアントにルーティングされます。元のリクエスターが存在しない場合、応答は黙って破棄されます。
Glib(そしてあまり役に立たない)の答えは、彼らがそのように書いたのでそれは機能するということです。
より長い答え:ZMQチームが行ったことは、ストリーム接続(ipcパイプ、ソケットなど)の上に独自のメッセージパッシングプロトコル(zmtp)を実装することです。メッセージの受け渡しと境界設定だけでなく、REQ/REP、PUB/SUB、均等化キューイングなどのさまざまなパターンをサポートする機能をこのプロトコルに組み込んでいます。これを機能させるために、zmqライブラリスレッドが実行されています。バックグラウンドでのすべてのzmtpアクティビティ、およびzmq_send、zmq_pollなどの呼び出しを介してこのスレッドと対話します。zmtpの使用は、ソケットのもう一方の端にあるプログラムもzmtpを話す必要があることを意味します。一方の端がlibzmqを使用していて、もう一方の端が単にrawソケットを開いている場合は、何も役に立ちません。
これは確かに非常に便利なコードです。
私の意見では、これは間違いなく進むべき道です。 ZMQは、実行の2つのスレッド間の接続の概念をうまく抽象化し、それらが同じマシン上にあるか、同じプロセス内にあるか、ネットワーク接続によって分離されているかなどを気にしなくなります。これにより、アプリケーション開発が容易になります。どこにでも行くことができます(ネットワークの速度と待ち時間に関連する問題を無視します)。
Zmqソケットを2つの異なるトランスポート(たとえば、ipcとtcpの両方)にバインドすることもできます。とても便利です!