質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1188閲覧

初質問です pythonでのsocket通信でクライアントを同時に処理開始させたい

Ayatakamaru

総合スコア3

Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2022/12/09 08:36

編集2022/12/12 09:13

前提

現在サーバー側Windows搭載のPC
クライアント側ラズパイ4が3台
このような構成になっています

実現したいこと

実現したことしては

  1. サーバで値を入力する。

2)3台のクライアントに同じ値を同時に送信
3) 3台のクライアントで処理を実施。
4) すべての結果を収集。
5) 1に戻る

最終的には、PC(サーバー)からの指令が来るたびにラズパイ(クライアント)が同時にプログラムを実行し
実行結果をサーバに返したいです

発生している問題・エラーメッセージ

エラーメッセージ

現在のプログラムだと一度通信を切らないと、サーバー側の数字が更新できない
whileループの中に入れると、複数台同時に送信できない、あるいは
Bad adressといったエラーがでる

該当のソースコード

サーバー側

python

1 2import socket 3import threading 4import time 5 6IPADDR = "" 7PORT = 8sock_sv = socket.socket(socket.AF_INET) 9sock_sv.bind((IPADDR, PORT)) 10sock_sv.listen(3) 11 12def recv_client(sock, addr): 13 try: 14 sock.send(signal.encode("utf-8")) 15 data = sock.recv(4096) 16 time.sleep(2) 17 print(data) 18 19 except ConnectionResetError: 20 pass 21 22while True: 23 signal=input("signal=") 24 25 sock_cl1, addr1 = sock_sv.accept() 26 sock_cl2, addr2 = sock_sv.accept() 27 sock_cl3, addr3 = sock_sv.accept() 28 29 thread1 = threading.Thread(target=recv_client, args=(sock_cl1, addr1)) 30 thread2 = threading.Thread(target=recv_client, args=(sock_cl2, addr2)) 31 thread3 = threading.Thread(target=recv_client, args=(sock_cl3, addr3)) 32 # スレッド処理開始 33 thread1.start() 34 thread2.start() 35 thread3.start() 36 #スレッド終了待ち合わせ 37 thread1.join() 38 thread2.join() 39 thread3.join() 40

クライアント側

python

1import socket 2import queue 3import threading 4import numpy as np 5import time 6 7IPADDR = "" 8PORT = 9sock =socket.socket(socket.AF_INET) 10sock.connect((IPADDR,PORT)) 11signal=0 12q= queue.Queue() 13 14def recv_data(sock): 15 while True: 16 try: 17 signal_data = sock.recv(1024) 18 print(signal_data.decode("utf-8")) 19 q.put(signal_data) 20 except ConnectionResetError: 21 break 22 sock.shutdown(socket.SHUT_RDWR) 23 sock.close() 24 25thread = threading.Thread(target=recv_data, args=(sock,)) 26thread.start() 27 28while True: 29 signal=q.get() 30 signal=float(signal) 31 try: 32 if signal > 0: 33 ser = serial.Serial("/dev/ttyS0", 38400,bytesize=7) 34 msg =ser.readline() 35 msg = msg.decode() 36 tok = msg.split(',') 37 S_data=tok[1]+","+tok[2]+","+tok[4] 38 S_data=str(S_data) 39    S_data=S_data+"signal= "+str(signal) 40 sock.send(S_data.encode("utf-8")) 41 42 else: 43 data=("error") 44 sock.send(data.encode("utf-8")) 45  except ConnectionResetError: 46  break 47 48sock.shutdown(socket.SHUT_RDWR) 49sock.close()

試したこと

ループ外にinputを設けるとエラーは起きないが、数字が更新できない
thread.start()の上にinputを設けると個々に数字を送るので同時に実行できない

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakaiY

2022/12/09 08:48

実現したい処理の流れがよくわかりません。 特にサーバ(PC)側での値の入力。 1) サーバで値を入力する。 2) 3台のクライアントで処理を実施。 3) すべての結果を収集。 4) 1に戻る でしょうか? それとも入力はクライアントごとに行ないたいのでしょうか?
Ayatakamaru

2022/12/09 09:10

処理の流れはTakaiYさんのおっしゃる通りです 入力は同じものを全クライアントを同時に送信したいです
dameo

2022/12/09 10:51

socket.ioのタグは外した方がいいです。あと初質問じゃないですよね? 前の同じような質問が削除申請中みたいです。
dameo

2022/12/09 11:07

クライアント3台から接続した後、例えばサーバー側から開始コマンドを決めて送ればいいかと思います。 クライアント側は送られたコマンドが開始コマンドなら処理を開始する、とかでしょうか・・・ サーバー側はacceptするスレッドを作成し、接続したソケットをリストか何かに並べておき、メインスレッドで開始の入力待ちをします。入力されたらスレッドを起動して接続したソケットの数分起動して、それぞれのスレッドで開始コマンドを送る、といった感じです。クライアントは今のままでいいでしょう。
Ayatakamaru

2022/12/10 03:10

すみません,前回の質問は編集方法が分からなかったので,新しく上げなおしたので全く同じものです 実現したいのはおっしゃる通りの手法です.クライアントの数だけスレッドを用意するイメージですか? あとメインループではなく,新しくスレッドで分けるってことですか?
dameo

2022/12/10 06:37

> クライアントの数だけスレッドを用意するイメージですか? 私が言ったのは(メインスレッドの他に)「クライアントの数+1」ですね > 新しくスレッドで分けるってことですか? 多分Yesです inputより前にacceptすることで、TCPの3Way Handshakeを事前に済ませています。1パケット届けばクライアントは処理を開始できます。
Ayatakamaru

2022/12/12 06:41

>>dameo acceptを別スレッドを移行せずに無事に同時に処理を開始することができましたが, 「inputより前にacceptすることで、TCPの3Way Handshakeを事前に済ませています。1パケット届けばクライアントは処理を開始できます。」 これをする利点がつかみ切れていません,知識不足で申し訳ないのですが,ご教授してもらえると助かります. クライアント側からの送信を接続を切らずに止めたいのですが,上記のことで解決できますでしょうか?
dameo

2022/12/12 07:15

利点は「同時に送信」の精度を上げる目的です。必要な精度が分からなかったので。 「クライアント側からの送信を接続を切らずに止めたい」はちょっと意味が分かりません。
Ayatakamaru

2022/12/12 07:42

現在稼働しているときは, 1)サーバで値を入力する。 2)3台のクライアントに同じ値を同時に送信 3) 3台のクライアントで処理を実施。 4) すべての結果を収集。 5) 1に戻る 1に戻れているのですが,クライアントから何度も結果が送られているので サーバ側から信号があれば,クライアントから一度(あるいは一定時間)のみ返事が来るようにしたいです プログラムを再起動とかは避けたいです
dameo

2022/12/12 07:48

すみません。プロトコルを決めれば済む話かと思いますが、それは別の質問ですね。 お手数ですが、別質問としてあげて他の方に聞いてください。
TakaiY

2022/12/12 07:53

「クライアントから何度も結果が送られている」は、何が送られてきているんでしょうか?
Ayatakamaru

2022/12/12 08:08

singal=1として入力するとsignal=1を利用した処理結果が送られ続けます signalは新しく入力を要求していますが,その間も結果が流れているので,信号入力毎に一度の処理といった形を実現したいです.
Ayatakamaru

2022/12/12 08:10

>>68user ありがとうございます.スレッド処理よりも良い点が分かれば使ってみます
dameo

2022/12/12 09:19

二度目ですが、当初の質問の回答は得られているので、ベストアンサーを選び、別の質問にしてください。
Ayatakamaru

2022/12/12 09:21

分かりました,ありがとうございます
guest

回答1

0

ベストアンサー

何ができていて何ができていないのか、提示されているコードではわからないので、外しているかもしれません。

サーバ側のループ処理はこういう感じになるはずです。
入力してスレッドを起動して終了待ち、を繰り返す。

python

1while true: 2 # 入力を求める。 3 signal=input("New signal>> ") 4 # スレッドをクライアント毎に起動する。 5 # thread生成は略 6 thread1.start() 7 thread2.start() 8 thread3.start() 9 # thread終了をまちあわせ 10 thread1.join() 11 thread2.join() 12 thread3.join() 13 # 必要であれば以下でthread結果の処理

で、現状のコードでは受信処理が無限ループになっています。これではthreadが終らなくて次に進めません。また、この中でソケットを止めてしまっては通信が継続しないのでそれも削除します。
で、以下のような感じでしょうか。(試していないのでバグあるはず。)
単にデータを送って結果を受け取ったら終了する感じ。

python

1def recv_client(sock, addr): 2 try: 3 sock.send(signal.encode("utf-8")) 4 data = sock.recv(1024) 5 print(data ) 6 except ConnectionResetError: 7 pass # 未検討

ちなみに、thread.Threadを使うとあまりスマートなコードになりません。(start()が並ぶような感じ)。
最近の、concurrent.futuerあたりを使うとスッキリ書けます。

投稿2022/12/09 10:27

TakaiY

総合スコア12747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ayatakamaru

2022/12/10 03:50

知識不足で本当にに申し訳ないのですが, sock_c1, addr1 = sock_sv.accept() thread1 = threading.Thread(target=recv_client, args=(sock_cl1, addr1)) sock_c2, addr2 = sock_sv.accept() thread2 = threading.Thread(target=recv_client, args=(sock_cl2, addr2)) であっていますか? 主な変更点としては,クライアント毎にスレッドの用意ってことですか? 試してみたとことjoinで終了した後,signalの再入力は求められますが,クライアントから結果が送られ続けます ここは止めれないでしょうか? concurrent.futuerのアドバイスありがとうございます。あまりにも散らかってきたら勉強してみます
TakaiY

2022/12/10 05:49

通信をどのように制御するかはシステム設計によるのですが、今の形だと、ループの中でなくて、事前に3台分の接続をしておいて、メッセージ(signalとdata)のみ送受信するかたちになると思います。 > クライアントから結果が送られ続けます 全部理解しながら見てはいませんが、サーバとクライアントのやりとりがうまくいっていないのであれば、まずは3台同時にとかでなく、1対1での通信ができるようにするのが先ではないでしょうか。 - ソケットの通信の開始はどの単位で実施するのか。 入力を受けてから socket 生成 -> signal送信 -> クライアントで処理 -> data返信 -> ソケット切断 (繰り返し) socket 生成 -> 入力 -> signal送信 -> クライアントで処理 -> data返信 (繰り返し or 何らかの切っ掛けで停止) -> ソケット切断
Ayatakamaru

2022/12/12 05:16

返事遅くなりました,申し訳ございません やり取りはできているのですが,クライアントからのデータ送信がサーバ側で止めれないです ① socket 生成 -> signal送信 -> クライアントで処理 -> data返信 -> ソケット切断 (繰り返し) この場合はサーバ側クライアント側を毎回プログラムを再起動して接続するってことですか? ②socket 生成 -> 入力 -> signal送信 -> クライアントで処理 -> data返信 (繰り返し or 何らかの切っ掛けで停止) -> ソケット切断 こちらが理想に近いです,接続を保ったまま送信の停止開始を操作したいです
TakaiY

2022/12/12 06:08

「クライアントからのデータ送信がサーバ側で止めれない」とのことですが、クライアントから何が送られてくるのですか?現状のソースであれば、サーバ側が何も送信しなければ、 q.get() で 止ってくれると思いますけど。
TakaiY

2022/12/12 08:32

「singal=1として入力するとsignal=1を利用した処理結果が送られ続けます」とのことですが、 - 質問を編集して、現状のソースコードを追加していただけますか。古いソースで話をしても意味がないので。 このとき、クライアント側も現状のものに更新してください。 - 送られ続けているのは、どうやって確認していますか?
Ayatakamaru

2022/12/12 08:33

シグナルを入力後も再入力せずに一度入力したシグナルでの結果をかえし続けています
TakaiY

2022/12/12 08:34

「かえし続けています」それはどうやって確認していますか?
Ayatakamaru

2022/12/12 08:49

クライアントで受信したsignalをサーバに送り返しています
Ayatakamaru

2022/12/12 09:15

ループのところを最新版にすると、返しつつづけることはなくなりましたが、新しくシグナルを入力してもクライアント側で受信できていません。エラーも出ずに止まっています
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問