モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

目次目次を開く/閉じる

ZeroMQ (zmq) の Python サンプルコード

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2018/06/05
最終更新最終更新
2021/09/07
記事区分記事区分
一般公開

目次

    プログラミング教育者。ScratchやPythonを教えています。

    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
    

    サーバー、クライアント Hello World

    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
    ↑接続はできても、応答が得られません。
    

    参考: socket を利用する場合

    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
    

    複数の zmq ソケットを監視 (zmq-poll)

    複数のファイルディスクリプタからのイベントを待つ 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 poll で生の TCP ソケットを監視

    zmq ソケットだけでなく、TCP ソケットのイベントも監視することができます。

    zmq_poll() shall examine either the ØMQ socket referenced by socket or the standard socket specified by the file descriptor fd
    http://api.zeromq.org/3-2:zmq-poll

    server_poll_2.py

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    from time import sleep
    from zmq import Context, REP, Poller, POLLIN
    
    from socket import socket as tpc_socket, AF_INET, SOCK_STREAM
    
    def Main():
        context = Context()
    
        socket1 = context.socket(REP)
        socket1.bind("tcp://*:15555")
    
        socket2 = context.socket(REP)
        socket2.bind("tcp://*:25555")
    
        tcp_socket = tpc_socket(AF_INET, SOCK_STREAM)
        tcp_socket.bind(('', 35555))
        tcp_socket.listen(1)
    
        poller = Poller()
        poller.register(socket1, POLLIN)
        poller.register(socket2, POLLIN)
        poller.register(tcp_socket, POLLIN)
    
        while True:
            try:
                socks = dict(poller.poll()) # クライアントからのメッセージ待ち
            except KeyboardInterrupt:
                break
    
            for socket in socks:
                if socket == tcp_socket.fileno():
                    conn, addr = tcp_socket.accept()
                    print('Established TCP connection with', addr)
                    while True:
                        data = conn.recv(1024)
                        if not data: break
                        conn.sendall(data)
                    conn.close()
                else:
                    message = socket.recv()
                    print("Received request: %s" % message)
                    sleep(1)
                    socket.send(b"World")
    
    if __name__ == '__main__':
        Main()
    

    client3.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', 35555))
        s.sendall(b'Hello world')
        data = s.recv(1024)
        print('Received', repr(data))
        s.close()
    
    if __name__ == '__main__':
        Main()
    

    Pub-Sub パターン

    クライアント側は unicode でフィルター文字列を指定できます。また Pub-Sub パターンでは接続前に Publish されたメッセージを取得しなくてもよい Subscriber を想定して実装します。

    server.py

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    import zmq
    
    def Main():
        context = zmq.Context()
        socket = context.socket(zmq.PUB)
        socket.bind('tcp://*:5556')
        while True:
            socket.send_string('aaa bbb ccc')
            socket.send_string('xxx yyy zzz')
    
    if __name__ == '__main__':
        Main()
    

    client.py

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    import zmq
    
    def Main():
        context = zmq.Context()
        socket = context.socket(zmq.SUB)
        socket.connect('tcp://localhost:5556')
    
        filter = u'xxx'
        socket.setsockopt_string(zmq.SUBSCRIBE, filter)
    
        for i in range(5):
            string = socket.recv_string()
            print(string)
    
    if __name__ == '__main__':
        Main()
    

    実行例

    python client.py
    xxx yyy zzz
    xxx yyy zzz
    xxx yyy zzz
    xxx yyy zzz
    xxx yyy zzz
    
    Likeボタン(off)0
    詳細設定を開く/閉じる
    アカウント プロフィール画像

    プログラミング教育者。ScratchやPythonを教えています。

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    >>さらに詳しくステッカーを贈る
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      ログインする

      関連記事