2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

オブジェクト間通信にUDPを使う

Posted at

オブジェクトの参照が面倒

オブジェクトが多くなってくるとオブジェクト同士の通信が億劫になってきます。親とか子とかパスとか、も~めんどくさい! たまには違うプログラムとやり取りなんかも発生して本当に大変。

ならばネットワークだ! 昔から利用されていた方法だから間違いはない。(はず)

お手軽通信、UDP

やっぱりこういう目的ならUDPでしょう。Open Sound Controlもちらっと考えたのですがモジュールとか導入したり諸々面倒なのでPythonで何も考えずに使えるudpで済ますことにしました。

受信を待つとかブロッキングで他の処理が止まるとかそういうのは使いづらくて困るのでデータが受信されたらコールバックが呼ばれるって感じで。

うん、なんか良さそうな気がしてきたぞ。

コード

そんな感じでとりあえずでっち上げました。行儀悪いところがあったりするけど細かいツッコミは必要ないので気になるなら直して使うなり自由にすると良いです。

比較的簡単に使える、気をつけなきゃいけないのはIPアドレスが被らないようにすることくらい。

udpnet.py

import socket
import threading


def thread(func):
    def run(*args, **kwargs):
        t = threading.Thread(target=func, args=args, kwargs=kwargs)
        t.start()
    return run

class UDP:
    def __init__(self, ADDR):
        self.addr = ADDR
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(self.addr)
        self.running = True
        self.callback = None

    def messageRecieved(self, callback=None):
        self.callback = callback
        
    @thread
    def mainloop(self):
        while self.running:
            try:
                data, addr = self.sock.recvfrom(8192)
            except:
                continue

            if data.decode() == "quit_request":
                break
            
            if self.callback:
                self.callback({"data": data.decode(),
                               "address": addr,
                               "sock": self})

    def send(self, msg, ADDR):     
        self.sock.sendto(msg.encode(), ADDR)

    def close(self):
        self.running = False
        self.send("quit_request", self.addr)
        self.sock.close()
        self.sock = None

使い方。

dict型のデータがやり取り出来れば不自由ないだろうということでそういうデモ。

二つのホストがやり取りするような内容。

つくった udpnet.py はあまり高速通信を得意とするような構造をしていないのでリアルタイムでだらだらデータストリーミングするような目的では使わない方が良いと思います。あくまでなにやらの処理のときにリクエスト → データを受け取って次の処理を呼ぶ。みたいな感じがよろしいかと。

import udpnet
import time
import json

# UDPホストその1 用のコールバック
# データの内容を表示して送信元へ返信を行う
def sevRcv(x):
    dat = json.loads(x["data"])
    for key in dat.keys():
        print(key, dat[key])
    x["sock"].send("welcome", x["address"]) 

#
# UDPホストその1
#
s0 = udpnet.UDP(("127.0.0.1", 49200))
s0.messageRecieved(sevRcv)
s0.mainloop()

#
# udpホストその2
#
s1 = udpnet.UDP(("127.0.0.2", 49200))
s1.mainloop()
# ホストその2 はコールバックをラムダで処理してみる
s1.messageRecieved(lambda x: print("recieved!:", x["data"]))

#
# 1秒おきに10回ほどホストその2から1へ送信をする
#
for i in range(10):
    dat = {"a": 123, "b": "hello"}
    s1.send(json.dumps(dat), ("127.0.0.1", 49200))
    time.sleep(1)

# ホストを閉じて終わり
s0.close()
s1.close()

まだ実戦投入してませんがヒエラルキーをガン無視できて大分自由に楽々になるんじゃないかと期待度高めです。

Pythonだとこういうのも簡単に書けていいですね。

さらなる展望としてはデータクラスと融合させて変数にアクセスするようなノリで通信が出来たらいいですねー。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?