ZeroMQ を Python から利用する場合のサンプルコードを記載します。
Fixing the World
To fix the world, we needed to do two things. One, to solve the general problem of "how to connect any code to any code, anywhere". Two, to wrap that up in the simplest possible building blocks that people could understand and use easily.
http://zguide.zeromq.org/py:all#Fixing-the-World
インストール例
sudo pip install zmq
server.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from time import sleep
from zmq import Context, REP
def Main():
context = Context()
socket = context.socket(REP)
socket.bind("tcp://*:5555")
while True:
# クライアントからのメッセージ待ち
message = socket.recv()
print("Received request: %s" % message)
sleep(1)
# 応答 (バイト列)
socket.send(b"World")
if __name__ == '__main__':
Main()
client.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from zmq import Context, REQ
def Main():
context = Context()
print("Connecting to hello world server...")
socket = context.socket(REQ)
socket.connect("tcp://localhost:5555")
for i in range(10):
socket.send(b"Hello")
message = socket.recv()
print("Received reply %s [ %s ]" % (i, message))
if __name__ == '__main__':
Main()
TCP 上の zmq のプロトコルで通信する必要があるため、そのままメッセージを送信しても応答はありません。また、サーバが起動していない状態でクライアントを起動しても、エラーとはならずにサーバが起動するまで待機します。
echo 'hello' | nc localhost 5555
↑接続はできても、応答が得られません。
生の TCP/IP ソケットプログラミングを行う場合は以下のようになります。
server.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from socket import socket, AF_INET, SOCK_STREAM
def Main():
s = socket(AF_INET, SOCK_STREAM)
s.bind(('', 5555))
s.listen(1) # backlog: the maximum length to which the queue of pending connections may grow.
conn, addr = s.accept() # 1接続と、1backlog → 2コネクションまで確立
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(data) # echo-back
conn.close()
s.close()
if __name__ == '__main__':
Main()
client.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from socket import socket, AF_INET, SOCK_STREAM
def Main():
s = socket(AF_INET, SOCK_STREAM)
s.connect(('localhost', 5555))
s.sendall(b'Hello world')
data = s.recv(1024)
print('Received', repr(data))
s.close()
if __name__ == '__main__':
Main()
zmq の場合と異なり、以下のコマンドでもサーバからの応答が得られます。
echo 'hello' | nc localhost 5555
複数のファイルディスクリプタからのイベントを待つ poll と似た構造で実装されている、複数の zmq ソケットからのイベント待ちを行う zmq-poll が利用できます。
server_poll.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from time import sleep
from zmq import Context, REP, Poller, POLLIN
def Main():
context = Context()
socket1 = context.socket(REP)
socket1.bind("tcp://*:15555")
socket2 = context.socket(REP)
socket2.bind("tcp://*:25555")
poller = Poller()
poller.register(socket1, POLLIN)
poller.register(socket2, POLLIN)
while True:
try:
socks = dict(poller.poll()) # クライアントからのメッセージ待ち
except KeyboardInterrupt:
break
for socket in socks:
message = socket.recv()
print("Received request: %s" % message)
sleep(1)
socket.send(b"World")
if __name__ == '__main__':
Main()
client1.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from zmq import Context, REQ
def Main():
context = Context()
print("Connecting to hello world server...")
socket = context.socket(REQ)
socket.connect("tcp://localhost:15555")
for i in range(10):
socket.send(b"Hello-1")
message = socket.recv()
print("Received reply %s [ %s ]" % (i, message))
if __name__ == '__main__':
Main()
client2.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from zmq import Context, REQ
def Main():
context = Context()
print("Connecting to hello world server...")
socket = context.socket(REQ)
socket.connect("tcp://localhost:25555")
for i in range(10):
socket.send(b"Hello-2")
message = socket.recv()
print("Received reply %s [ %s ]" % (i, message))
if __name__ == '__main__':
Main()
実行例
サーバ
$ python server_poll.py
Received request: Hello-1
Received request: Hello-1
Received request: Hello-1
Received request: Hello-2
Received request: Hello-2
Received request: Hello-2
Received request: Hello-1
Received request: Hello-2
Received request: Hello-1
Received request: Hello-2
Received request: Hello-1
Received request: Hello-2
Received request: Hello-1
Received request: Hello-2
...
クライアント1
$ python client1.py
Connecting to hello world server...
Received reply 0 [ World ]
Received reply 1 [ World ]
Received reply 2 [ World ]
Received reply 3 [ World ]
Received reply 4 [ World ]
...
クライアント2
$ python client2.py
Connecting to hello world server...
Received reply 0 [ World ]
Received reply 1 [ World ]
Received reply 2 [ World ]
Received reply 3 [ World ]
...
zmq ソケットだけでなく、TCP ソケットのイベントも監視することができます。