IoT+WEBのためのホームサーバ計画の実装編4。そもそも複数のスレッドをどう統合して仕上げるのかって話(o^^o)
2020-02-24 2020-02-26
だいぶ進んできたので。
IoTコントローラも、HomeServerも、Web側のWebSocketサーバも、
全てマルチスレッドで(一部マルチプロセスで)動作してるわけで、
そうすると、スレッド間とかプロセス間をどうやって連携させるかって話が当然あるわけです。
こっちでTCPでとんできたものを、あっちにWebSocketするとかそういう時ですね。
そういうときは、まず、それを統合するクラスから作りますってのが私的に好きな方法です。
どうやってI/Fをとるのかっていうと
では、サンプルから。
WebSocketサーバ側の一部です。
import const
import threading
from websocket_server import WebsocketServer
from hiraSERVER import hiraSERVER
#--------------------------------------
class hiraWS:
#---------------------------------------
#
#---------------------------------------
def __init__(self, host, port, funcs = None):
self.server = WebsocketServer(port,host=host)
self.dolly = funcs
#---------------------------------------
# サーバーを起動する
#---------------------------------------
def run(self,S):
S.setWSServer(self.server)
self.server.set_fn_new_client(S.new_client) # クライアント接続時CALLBACK
self.server.set_fn_client_left(S.client_left) # クライアント切断時CALLBACK
self.server.set_fn_message_received(S.message_received) # メッセージ受信時CALLBACK
self.server.run_forever()
#---------------------------------------
#
#---------------------------------------
def createWS(S):
W = hiraWS("0.0.0.0",const.HIRA_USE_WS_PORT)
W.run(S)
#---------------------------------------
#----------------------------------
if __name__ == '__main__':
S = hiraSERVER()
Q = threading.Thread(target = hiraWS.createWS,args=(S,))
Q.start()
P = threading.Thread(target = xxxxxxx,args=(S,))
P.start()
import hiraSetting
#--------------------------------------
class hiraSERVER:
#WevSocketClient AR
clAR = []
#---------------------------------------
# idからクライアントを特定する
#---------------------------------------
def searchClient(self, id):
n = len(self.clAR)
for w in range(n):
if self.clAR[w]['client']['id'] == id:
return self.clAR[w]['client']
return None
#---------------------------------------
# idからクライアントリストから削除する
#---------------------------------------
def deleteClient(self, id):
n = len(self.clAR)
for w in range(n):
if self.clAR[w]['client']['id'] == id:
del self.clAR[w]
print("delete client @ ",id)
break
print("client list len:",len(self.clAR))
#---------------------------------------
#
#---------------------------------------
def setWSServer(self,SV):
self.wsserver = SV
#---------------------------------------
# クライアント接続時に呼ばれる関数
#---------------------------------------
def new_client(self, client, server):
print("new client connected and was given id {}".format(client['id']))
# 全クライアントにメッセージを送信
#self.wsserver.send_message_to_all("hey all, a new client has joined us")
#self.client = client
print("cl:",client) #clientはid,handler,addressをもっている
print("sv:",server)
o = {"client":client,"data":{}}
self.clAR.append(o)
self.wsserver.send_message(client,"welcome to WSSERVER. your id is " + str(client["id"]))
#---------------------------------------
# クライアント切断時に呼ばれる関数
#---------------------------------------
def client_left(self, client, server):
print("client({}) disconnected".format(client['id']))
id = client['id']
self.deleteClient(id)
#---------------------------------------
# クライアントからメッセージを受信したときに呼ばれる関数
#---------------------------------------
def message_received(self, client, server, message):
print("client({}) said: {}".format(client['id'], message))
self.wsserver.send_message_to_all(message.encode('utf-8')) # 全クライアント送信
#個別への送り方
#cl = self.wsserver.searchClient(1)
#self.wsserver.server.send_message(cl,"message from server だよーー".encode('utf-8'));
#---------------------------------------
#----------------------------------
こうやってます
S = hiraSERVER()
Q = threading.Thread(target = hiraWS.createWS,args=(S,))
Q.start()
そうですね。まず、hiraSERVERが統合クラスなわけで、 、
それを生成したのち、
他のスレッドを生成するときに、統合クラスのインスタンスを渡すだけです。
またスレッドに渡す関数は、生成スレッドのクラスの中の
STATICな関数を渡します。
なんか、C++でやってたときのノリそのまんまなんですけどね。
それで、STATICな関数(ここではcreateWS)の中でインスタンスを生成、
そして、必要なものを渡したりして(ここではrunの中の、、S.setWSServer(self.server)のとことか)
そうすれば、WebSocketから受信したときも、
WebSocketに送信するときも、
他のスレッドのTCPを受信したときとかも、
全てこの1つのクラスの中で連携させて、完結させようという方法です。
ポインタじゃなきゃダメってときはスレッド、
その他でもOKなときは、multiprocessing.Processでも良いってことになります。
おわり(o^^o)