質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

2111閲覧

pyzmq ブローカーを作成したい

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2017/03/29 01:36

クライアント→サーバー←クライアントという風にクライアントの仲介役を作成したいです

http://pyzmq.readthedocs.io/en/latest/index.html
前回の質問で貼ってくださったこれに目を通してみたものの自分には難しくて手がかりが掴めず

仲介役を挟みたいクライアントのコードはこんな感じです

python

1mport zmq 2 3#クライアント 4 5host="127.0.0.1" 6port=6789 7 8context=zmq.Context() 9client=context.socket(zmq.REQ) 10client.connect("tcp://%s:%s"%(host,port)) 11 12y=90 13client.send_pyobj(y) 14 15x=client.recv_pyobj() 16print(x)

python

1import zmq 2 3#クライアント 4 5host="127.0.0.1" 6port=6789 7 8context=zmq.Context() 9client=context.socket(zmq.REQ) 10client.connect("tcp://%s:%s"%(host,port)) 11 12y=50 13client.send_pyobj(y) 14 15x=client.recv_pyobj() 16print(x)

片方は50の数値を送り、もう片方は90の数値を送るプログラムですが
これらを起動しても、両方が同期要求をする為、何も動きません
この間に、仲介役のサーバーを作成して反対側のクライアントに情報を渡したいわけです

自分がイメージしているサーバーはこんな感じです

python

1import zmq 2 3#サーバー 4 5host="127.0.0.1" 6port=6789 7 8context=zmq.Context() 9server=context.socket(zmq.REP) 10server.bind("tcp://%s:%s"%(host,port)) 11 12x=server.recv_pyobj() 13 14server.send_pyobj(x)

受け取った値をそのまま返すサーバーです
後はこれを複数のメッセージや、複数のクライアントとやり取りが出来るように変形すればいいのかなと思っているのですが、その複数のやり取りがどうすればいいのかわからなくて...

わかる方いらしたらよろしくお願いします

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

REQ/REPが一方向の場合のブローカ/クライアント/ワーカー(サーバー)例は2.2.7 共有キュー (DEALER and ROUTER sockets)Shared Queue (DEALER and ROUTER sockets)
にあるとおり、比較的簡単に記述できます。

しかし、お互いがREQ/REPしあう場合はちょっと複雑になりそうです。
とりあえず以下のような動作をするサンプルを作成してみました。

  • AliceBobという2人がいる。
  • Aliceclient(REQ)Bobworker(REP)であるが、途中で仕事を代わることができる。
  • clientが送信した数値をworkerは+1して返す。
  • ブローカはAlice->BobBob->Alice の両方向を仲介する。

client_worker.py

Python

1import zmq 2 3# client動作 : 入力値を送信し結果を取得する 4# 入力値が0ならworkerになる 5def clientProc( client): 6 print("client start") 7 send = int(input("input number(0 to change worker):")) 8 client.send_pyobj(send) 9 recv = client.recv_pyobj() 10 print("client recv[%s] end" %(str(recv))) 11 return send 12 13# worker動作 : 受信値に+1した値を返す 14# 受信値が0ならclientになる 15def workerProc( worker): 16 print("worker start") 17 recv = worker.recv_pyobj() 18 print("worker recv[%s]"%(str(recv))) 19 send = recv + 1 20 worker.send_pyobj(send) 21 print("worker end") 22 return recv 23 24if __name__ == '__main__': 25 26 ctx = zmq.Context() 27 role = input("role ? [a]=Alice or [b]=Bob :") 28 29 if role == "a": # Alice : 最初はclient 30 port = [6710,6721]; job = "client" 31 elif role == "b": # Bob : 最初はworker 32 port = [6720,6711]; job = "worker" 33 34 client = ctx.socket(zmq.REQ); client.connect("tcp://127.0.0.1:%d"%(port[0])) 35 worker = ctx.socket(zmq.REP); worker.connect("tcp://127.0.0.1:%d"%(port[1])) 36 37 while True: 38 if job == "client": 39 ret = clientProc( client) 40 if ret == 0: job = "worker" 41 else: 42 ret = workerProc(worker) 43 if ret == 0: job = "client" 44 45 print("end")

broker.py : Alice/Bob間の相方向にブローカ動作する

Python

1import zmq 2 3if __name__ == '__main__': 4 ctx = zmq.Context() 5 6 # Alice -> Bob 7 reqA2B = ctx.socket(zmq.ROUTER); reqA2B.bind("tcp://127.0.0.1:6710") 8 resA2B = ctx.socket(zmq.DEALER); resA2B.bind("tcp://127.0.0.1:6711") 9 10 # Bob -> Alice 11 reqB2A = ctx.socket(zmq.ROUTER); reqB2A.bind("tcp://127.0.0.1:6720") 12 resB2A = ctx.socket(zmq.DEALER); resB2A.bind("tcp://127.0.0.1:6721") 13 14 print("broker start") 15 16 # Initialize poll set 17 poller = zmq.Poller() 18 poller.register(reqB2A, zmq.POLLIN); poller.register(resB2A, zmq.POLLIN) 19 poller.register(reqA2B, zmq.POLLIN); poller.register(resA2B, zmq.POLLIN) 20 21 # Switch messages between sockets 22 while True: 23 socks = dict(poller.poll()) 24 25 if socks.get(reqB2A) == zmq.POLLIN: 26 msg = reqB2A.recv_multipart() # from Bob 27 print("Request : Bob -> Alice[%s]"%(str(msg))) 28 resB2A.send_multipart(msg) # to Alice 29 30 if socks.get(resB2A) == zmq.POLLIN: 31 msg = resB2A.recv_multipart() # from Alice 32 print("Response : Alice -> Bob[%s]"%(str(msg))) 33 reqB2A.send_multipart(msg) # to Bob 34 35 if socks.get(reqA2B) == zmq.POLLIN: 36 msg = reqA2B.recv_multipart() # from Alice 37 print("Request : Alice -> Bob[%s]"%(str(msg))) 38 resA2B.send_multipart(msg) # to Bob 39 40 if socks.get(resA2B) == zmq.POLLIN: 41 msg = resA2B.recv_multipart() # from Bob 42 print("Response : Bob -> Alice[%s]"%(str(msg))) 43 reqA2B.send_multipart(msg) # to Alice 44 45 print("broker end")

以上のように、ちょっと複雑です。
そもそも、もっとよいメッセージングパターンがあるような気がしますので、ガイドブックを一読することを勧めます。

ブローカ例を追加

REQ/REP一方向だけであれば、以下のように簡潔に記述できます。
両方向分、2プロセス立ち上げる必要ありますが、こちらのほうがお勧めです。

broker2.py : Alice->Bob or Bob->Aliceいずれか一方向のブローカ動作する。起動時に選択する。

Python

1import zmq 2if __name__ == '__main__': 3 ctx = zmq.Context() 4 role = input("Broker role ? [a]=Alice->Bob or [b]=Bob->Alice :") 5 if role == "a": port = [6710,6711] 6 elif role == "b": port = [6720,6721] 7 8 print("broker start") 9 req = ctx.socket(zmq.ROUTER); req.bind("tcp://127.0.0.1:%d"%(port[0])) 10 res = ctx.socket(zmq.DEALER); res.bind("tcp://127.0.0.1:%d"%(port[1])) 11 zmq.proxy( req,res) 12 print("broker end")

投稿2017/03/29 09:46

編集2017/03/29 11:14
can110

総合スコア38234

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/03/29 10:35

なるほど、ありがとうございます 自分が思ってたよりも複雑になるんですね... もっと簡単に出来るもんだと思ってました... サンプルコードまでありがとうございます 現状読み解けそうにないので、理解できるまで勉強してみようと思います
can110

2017/03/29 11:16

ブローカは一方向でプロセス(.py)毎にすると簡潔になるのでサンプル追加しました。 実際に動かすと動作は理解しやすいかと思います。
退会済みユーザー

退会済みユーザー

2017/03/29 13:31

ありがとうございます! 元々、色々検索しても英語のサイトばかりだったり、言葉が難しかったりして、入門python3の書籍に書いてあった数少ない説明と、サンプルコードから自分なりに読み解いた程度の知識しかなかったのですが、追記してくださったコードを眺めてたら、色んなもやもやが解けました まず、プロセス毎に同期応答やら同期要求やらが一括りになっているものだと思っていましたがメッセージ毎に決められるんですね そして複数のメッセージのやり取りの仕方もわかっていなかったのですが、これをするにはもう一つポートを作ってやればいいんですね 自分が張ったコードの下の3行に関しては決まり事として認識していたんですが、おかげ様で何をしているか理解する事が出来ました context=zmq.Context() client=context.socket(zmq.REQ) client.connect("tcp://%s:%s"%(host,port)) 正直自分が理解できる情報が少なくて、どうすればいいのか手がかりがまったく掴めていなかったのですが、何をすればいいか見えてきました 改めてありがとうございます 本当に助かりました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問