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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Socket.IO

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

Q&A

解決済

2回答

3796閲覧

PCとラズパイ間のソケット通信

suhsuu

総合スコア15

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Socket.IO

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

0グッド

0クリップ

投稿2019/05/01 01:55

前提・実現したいこと

クライアントであるラズパイ2台(A,B)と、PC間で通信をさせています。
A、Bそれぞれは、PCからのプログラムスタートの指示(文字列'start')を受け、ある処理をした後に処理終了の時刻を示す文字列(sc_time)をPCへ送信します。
PCは、A、Bから受けた2つの時刻の差(del_sec)が5秒以下であれば、その2つの時刻を表示する。もし一方から処理終了を受けてから5秒を超えると、もう一方からの連絡を受けることなく両者にプログラム再スタートの指示を出すということをさせたいです。

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

両者からの連絡の差が5秒以内のときは予定通り動作するのですが、再スタートの指示を出すときにプログラムが止まったままになってしまいます。
具体的には、Aから連絡を受けたのち5秒経ったので、両者に再スタートの指示を出す段階で、'Order to Rpi:sc-a start' は表示されますが 'Order to Rpi:sc-b start' がいつまで経っても表示されません。つまり、プログラムが order_to_client_sock(host_address, host_port_for_b, 'start') で止まってしまいます。

該当のソースコード

Python3

1サーバー側 2 3import threading 4import datetime 5import logging 6import time 7import socket 8 9def order_to_client_sock(host_address, host_port, message): 10 backlog = 1 11 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 12 s.bind((host_address, host_port)) 13 s.listen(backlog) 14 conn, addr = s.accept() 15 # クライアントにメッセージを送る 16 message_bytes = message.encode('utf-8') #文字列をバイト型に変換 17 conn.sendall(message_bytes) 18 19def receive_stamp_by_sock(timeout, host_address, host_port): 20 stamp_str = b'' 21 try: 22 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 23 backlog = 1 24 s.bind((host_address, host_port)) 25 s.listen(backlog) 26 s.settimeout(timeout) 27 conn, addr = s.accept() 28 29 ## クライアントから文字列を受ける 30 stamp_bytes = conn.recv(1024) 31 #バイト型を文字列変数に変換 32 stamp_str = stamp_bytes.rstrip().decode("UTF-8") 33 except socket.timeout: 34 s.close() 35 return stamp_str 36 37def receive_sc_time_sock(host_address, host_port): 38 logging.debug('start') 39 global STOP_FLAG 40 global SC_TIME_LIST 41 sc_time = '' 42 43 while len(sc_time) == 0: 44 sc_time = receive_stamp_by_sock(1, host_address, host_port) 45 logging.debug(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")) 46 if STOP_FLAG == True: 47 break 48 SC_TIME_LIST.append(sc_time) 49 logging.debug('end') 50 51if __name__=='__main__': 52 check_flag = True 53 host_address = '192.168.137.1' 54 host_port_for_a = 50007 55 host_port_for_b = 50008 56 del_sec = 5 57 58 while True: 59 #端末A,Bへプログラムスタートを指示する'start'を送信 60 order_to_client_sock(host_address, host_port_for_a, 'start') 61 logging.debug('Order to Rpi:sc-a start') 62 order_to_client_sock(host_address, host_port_for_b, 'start') 63 logging.debug('Order to Rpi:sc-b start') 64 65 SC_TIME_LIST = [] 66 STOP_FLAG = False 67 check_flag = True 68 69 #端末A,Bから信号が受信されるのを待つ 70 thread_obj_a = threading.Thread( 71 target=receive_sc_time_sock, 72 args=(host_address, host_port_for_a)) 73 thread_obj_b = threading.Thread( 74 target=receive_sc_time_sock, 75 args=(host_address, host_port_for_b)) 76 thread_obj_a.start() 77 thread_obj_b.start() 78 79 while len(SC_TIME_LIST) == 0: 80 time.sleep(0.1) 81 signal_time1 = datetime.datetime.now() #第一信号 取得時刻 82 83 while not len(SC_TIME_LIST) == 2: 84 check_time = datetime.datetime.now() #第二信号 取得時刻 85 86 if check_time > signal_time1 + datetime.timedelta(seconds=del_sec): 87 check_flag = False 88 STOP_FLAG = True 89 thread_obj_a.join() 90 thread_obj_b.join() 91 logging.debug('Both threads end') 92 break 93 else: 94 continue 95 if not check_flag == False: 96 break 97 print(SC_TIME_LIST) 98 99 100クライアント側 101 省略

試したこと

タイムアウトの設定やソケットを閉じる動作に問題があるのではないかと試行錯誤してみましたが、解決に至りませんでした。

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

PC側、ラズパイ側ともにPython3.5

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

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

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

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

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

otolab

2019/05/01 02:55

ラズパイが荷台なのに、アドレス(host_address)が一つに見えるのが気になります。 これはテスト用のコードですか?
suhsuu

2019/05/01 03:02

PC側のアドレスなので一つですね。二台のラズパイに向けてポート2つ(50007と50008)を準備してます。
otolab

2019/05/01 03:19

ああ失礼しました、どの通信もPC側で接続されるのを待ち受けるんですね。 PC側から通信に行く処理ではないので、クライアント側の該当部分のコードも必要になってくる気がします。 order_to_client_sockの中のどの段階で止まっているのか、もう少し詳細に調べても良いかもしれません。
suhsuu

2019/05/02 00:48

どの段階で止まっているのか、もう少し詳細に調べる方がよい・・・ とても良いヒントをもらいました。 早速、調べてみると、bind,listenまでは進行し、acceptで止まっていました。
suhsuu

2019/05/02 00:51

追伸: acceptで止まっているということは、クライアント側の準備を待っている、つまり、処理が停滞している原因はクライアント側にあるということでしょうか。
otolab

2019/05/02 04:17

そうですね。 クライアントからの接続を待ち受けて、そのまま待ちぼうけ状態っぽいですね。 次は「クライアント側の状態がどうなっているのかの把握」でしょうか。 この段階だとクライアントのプログラムもPC側で動かしたり、ダミーの処理で動くようにして「連携部分だけ確認する」ようにすると作業が進めやすいと思います。
suhsuu

2019/05/02 12:10

クライアント側で処理をさせるのと並行して、order_to_client_sockによる信号を受信できるようにクライアント側のプログラムを組まないといけないようですね。
guest

回答2

0

自己解決

改善すべき箇所が少しは明確になりました。
クライアント側で処理をさせるのと並行して、order_to_client_sockによる信号を受信できるようにクライアント側のプログラムを組まないといけないようです。

投稿2019/05/02 12:12

suhsuu

総合スコア15

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

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

0

実際にプログラムを動かして、検証していなくて、目視した感じで、間違ったら、すみません。

while trueのループに、

order_to_client_sockがあります。

order_to_client_sockに

s.bind((host_address, host_port)) s.listen(backlog)

があります。

つまり、s.bindは複数回実行されることになり得るということで

1回目はいけますが

2回目以降は、そのhost_address, host_portはすでに一回目で使われていると思われます。コネクションは張れません(host_address, host_portはどこかで解放されているなら、すみません)。

この線で、見ていけば、デバッグできるかもしれません。

ご参考になれば幸いです。

投稿2019/05/01 09:04

kawashimaken

総合スコア51

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

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

suhsuu

2019/05/01 12:34

コメントありがとうございます。 with文のブロックのなかに入れているので、必ず毎回closeされていると考えています。 念のため、with文のブロック最後にs.close()を追加して実行しても、動作は同じでした。 つまり、期待する動作にはなりませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問