はじめに
以前書いた記事 が、1リクエストずつしか処理できない形になっていたので、マルチスレッド化して多重化(同時処理)できるようにしたサンプルプログラム。
backlog(ドキュメント読んだ限りでは受信可能数)という引数設定があったため、勝手にやってくれるのかと勘違い…。
環境
- windows10 pro
- wsl2(20.04.5 LTS (Focal Fossa))
- Dockerのバージョン
- Docker version 20.10.18, build b40c2f6
- docker-compose version 1.29.2, build 5becea4c
※Docker Desktop ではありません
※通信のリクエストは、Windowsからも行っています
- python 3.10.7
- コンテナのポート設定については
ports:
- 50000:50000
を入れています
コード
receive.py
import socket
from concurrent.futures import ThreadPoolExecutor
import time
# 受信IP
RCV_HOST = "0.0.0.0"
# 受信ポート
RCV_PORT = 50000
# 受信可能数(指定以上超えると、待ちが発生せずに処理終了??)
BACKLOG = 10
# 一度の通信受信できる最大データバイト数
BUFSIZE = 1024
# 最大同時処理数
MAXWORKER = 10
# 受信~返信処理
def data_comminicate(conn):
while True:
try:
# 通信を受信
rcv_msg = conn.recv(BUFSIZE)
# 内容がないときは、処理をしない
if not rcv_msg:
break
# 受信内容の確認
print("rcv_msg:", rcv_msg)
# 多重化しているかの確認(ここに受信データを使った処理を記載)
print("before sleep:", rcv_msg)
time.sleep(10)
print("after sleep:", rcv_msg)
# 返信処理
conn.send(b":Received - " + rcv_msg)
except Exception as e:
break
finally:
conn.close()
if __name__ == "__main__":
try:
# ソケット定義
sct = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 再使用設定(3つ目の引数は違う可能性あり)
sct.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, BACKLOG)
# 受信設定
sct.bind((RCV_HOST, RCV_PORT))
sct.listen(BACKLOG)
# マルチプロセスで実行
with ThreadPoolExecutor(MAXWORKER) as executor:
# 継続受信のため、ループ
while True:
try:
# コネクション定義(切断処理の判定対策)
conn = None
# 受信の待機
(conn, addr) = sct.accept()
# マルチプロセスで データ受信~返信を実行
executor.submit(data_comminicate, conn)
except KeyboardInterrupt as e:
# キーボード(ctrl+c等)で抜けたとき
print("KeyboardInterrupt", e)
finally:
# 受信せずに終わる場合(ctrl+c等)は、処理を抜けさせる
if conn is None:
break
except Exception as e:
# socketオブジェクトの定義ミス
print("socket variable error", e)
finally:
# socketオブジェクト終了
sct.close()
最後に
あまり自分の意向に沿った記事が見つけられなかったため、bing
の AI
チャットで concurrent.futures の ThreadPoolExecutor を使った socketの多重化サンプルプログラムが欲しい
みたいなキーワードで生成させると、かなり意向に沿った感じのサンプルを作成してくれました。
threadpoolexecutor で…とするとpythonのデフォルトパッケージではなく、threadingでやると…というような回答が来ましたので、調整は面倒ですが、なかなか面白くもあるなと思った次第です。