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

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

ただいまの
回答率

89.13%

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

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 995

suhsuu

score 15

前提・実現したいこと

クライアントであるラズパイ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') で止まってしまいます。

該当のソースコード

サーバー側

import threading
import datetime
import logging
import time
import socket

def order_to_client_sock(host_address, host_port, message):
    backlog = 1
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind((host_address, host_port))
        s.listen(backlog)
        conn, addr = s.accept()
        # クライアントにメッセージを送る
        message_bytes = message.encode('utf-8')  #文字列をバイト型に変換        
        conn.sendall(message_bytes)

def receive_stamp_by_sock(timeout, host_address, host_port):
    stamp_str = b''
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 
            backlog = 1
            s.bind((host_address, host_port))
            s.listen(backlog)
            s.settimeout(timeout)
            conn, addr = s.accept()

            ## クライアントから文字列を受ける      
            stamp_bytes = conn.recv(1024)
            #バイト型を文字列変数に変換
            stamp_str = stamp_bytes.rstrip().decode("UTF-8")
    except socket.timeout:
        s.close()
    return stamp_str

def receive_sc_time_sock(host_address, host_port):
    logging.debug('start')
    global STOP_FLAG
    global SC_TIME_LIST
    sc_time = ''

    while len(sc_time) == 0:
        sc_time = receive_stamp_by_sock(1, host_address, host_port)
        logging.debug(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S"))
        if STOP_FLAG == True:
            break
    SC_TIME_LIST.append(sc_time)
    logging.debug('end') 

if __name__=='__main__':  
    check_flag = True
    host_address = '192.168.137.1'    
    host_port_for_a = 50007
    host_port_for_b = 50008
    del_sec = 5

    while True:
        #端末A,Bへプログラムスタートを指示する'start'を送信
        order_to_client_sock(host_address, host_port_for_a, 'start')
        logging.debug('Order to Rpi:sc-a start')
        order_to_client_sock(host_address, host_port_for_b, 'start')
        logging.debug('Order to Rpi:sc-b start')

        SC_TIME_LIST = []
        STOP_FLAG = False 
        check_flag = True

        #端末A,Bから信号が受信されるのを待つ
        thread_obj_a = threading.Thread(
                target=receive_sc_time_sock,
                args=(host_address, host_port_for_a))
        thread_obj_b = threading.Thread(
                target=receive_sc_time_sock,
                args=(host_address, host_port_for_b))
        thread_obj_a.start()
        thread_obj_b.start()

        while len(SC_TIME_LIST) == 0:
            time.sleep(0.1)
            signal_time1 = datetime.datetime.now() #第一信号 取得時刻

        while not len(SC_TIME_LIST) == 2:
            check_time = datetime.datetime.now() #第二信号 取得時刻

            if check_time > signal_time1 + datetime.timedelta(seconds=del_sec):
                check_flag = False
                STOP_FLAG = True
                thread_obj_a.join()
                thread_obj_b.join()
                logging.debug('Both threads end')
                break
            else:
                continue
        if not check_flag == False:
            break
       print(SC_TIME_LIST)


クライアント側
 省略

試したこと

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • suhsuu

    2019/05/02 09:51

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

    キャンセル

  • otolab

    2019/05/02 13:17

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

    キャンセル

  • suhsuu

    2019/05/02 21:10

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

    キャンセル

回答 2

check解決した方法

0

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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 21:34

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

    キャンセル

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

  • ただいまの回答率 89.13%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる