Python
マルチスレッド
udp

Python3系にてマルチスレッドでUDP通信

主に自分用のメモです。

はじめに

  • Pythonでメインのプログラムの傍らUDP通信をしたい
  • マルチスレッドで通信内容を共有したい

ということで複数スレッドを立てて,片方のスレッドでUDPを受信しつつもう片方のスレッドで別の作業をできるようにします。

参考にしたページ群を以下に追記していきます。
- https://qiita.com/slowsingle/items/20d4d601a85470725eb3

マルチスレッド

簡単なマルチスレッドでよければPythonのthreadingを用います。

UDP通信

以下の記事をソケット通信実装の参考にしました。

UDP通信とマルチスレッドに関する記事はTCPで通信しており,UDPに変える必要がありますね。

UDP クライアント

標準入力から入力を取得して送信するクライアントのプログラムをかきました。

client.py

# coding: utf-8
from socket import *
HOST = gethostname()
PORT = 34512
BUFSIZE = 1024
ADDR = (gethostbyname(HOST), PORT)
USER = 'Client'
udpClntSock = socket(AF_INET, SOCK_DGRAM)
while True:
    data = input('%s > ' % USER) # 標準入力からのデータ入力
    udpClntSock.sendto(data.encode('utf-8'), ADDR) # データ送信
    #udpClntSock.setblocking(0)# Non blocking
    if not data:
        break
udpClntSock.close()

UDPなのでソケットを作ってぶち込むだけです。

サーバー側

サーバー側では別のスレッドを立ててそこで受信を待ちつつ,main関数で受信した文字列を閲覧しています。
グローバル変数でも良いらしいですが,クラス変数を参照することによってわかりやすくなっています。

自分的ポイントは

  • クラスの定義でThreadを継承
  • 受信データをクラス変数に格納してmainで読めば良い

ってとこでしょうか。

import threading
import time
from socket import *

class ServerThread(threading.Thread):
    def __init__(self, PORT=34512):
        threading.Thread.__init__(self)
        self.data = 'hoge'
        self.kill_flag = False
        # line information
        self.HOST = gethostname()
        self.PORT = PORT
        self.BUFSIZE = 1024
        self.ADDR = (gethostbyname(self.HOST), self.PORT)
        # bind
        self.udpServSock = socket(AF_INET, SOCK_DGRAM)
        self.udpServSock.bind(self.ADDR) # HOST, PORTでbinding

    def run(self):
        while True:
            try:
                data, self.addr = self.udpServSock.recvfrom(self.BUFSIZE) # データ受信
                self.data = data.decode()
            except:
                pass

if __name__ == '__main__':
    th = ServerThread()
    th.setDaemon(True)
    th.start()

    while True:
        if not th.data:
            break
        print(th.data)
        time.sleep(0.1)

UDPサーバー

非同期通信を行ったブログが参考になります。

メモなど

strとbyte型の変換

Python3ではソケットを送る際にstr型からbyte型への変換を求められます。

str型はともかく,byte型とはb'hogefuga'で表される文字列で,''の前にbを入れればOKです。

また,encodeとdecodeで変換できます。

>>> 'hogefuga'.encode('utf-8')
b'hogefuga'
>>> b'hogefuga'.decode('utf-8')
'hogefuga'

このutf-8を入力しないでも一応変換してくれますがデフォルトの変換がどのようなものかわからないので一応入れておくようにしましょう。

非同期通信を用いる

マルチスレッドの他にもノンブロッキングプロセスという仕組みを用いて通信待ちをしながら別の処理ができます。
気が向いたら追記します(PCの電池が切れそう)

ノンブロッキングプロセスに関してはこちら