rasberry pi 3 で 計数カウンタを作成する6 -ソケット通信 クライアント再接続

さて、前回カウンターの値を、ソケット通信でサーバに接続して、

送るところまでやりましたが、

 

サーバを一度落としてしまうと、

サーバが再起動しても、クライアントの再接続がなかなかできず、苦労しました。

 

最終的に実現した方法は。

① カウントのプログラムは独立させて、カウントをテキストに記録し続ける。

② 通信プログラムを用意し、カウントのテキストを読み込んで、サーバに送信する。

③ サーバへの送信に失敗したら、シェルスクリプトを使用して、通信プログラムを再起動し、自分は終了する。

④ 通信プログラムは接続できるまで待機し続けるので、サーバが再起動されると、再接続される。

 

最初は計数のカウントと通信を同時にpython でやろうとしたのですが、

計数カウントを取り続けながら、サーバへ再接続するのが難しくて、

分離して単純化しました。

 

通信プログラムで、サーバへの送信が失敗した時に、単純に再接続しようとしましたが、うまくいきませんでした。再接続不能になるか、何度も接続と切断を繰り返してしまうような挙動になってしまいました。

うまくいかないので、通信プログラム自体を再起動することにし、シェルスクリプトで実装しました。

 

以下、新しいカウンターのプログラム

 

import RPi.GPIO as GPIO
import struct
import time
from time import sleep
import socket
import sys

def write_count(count):
    f = open('/home/XXXXX/count.txt' ,'w')
    f.write(str(count))
    f.close()

def callBackRising(channel):
    if GPIO.input(24):
    # GPIO.output(25,GPIO.HIGH)
    global count
    count += 1
    try:
        print(str(count))
        write_count(count)
    except:
        pass
    else :
        pass
        # GPIO.output(25,GPIO.LOW)
def read_do():
    f = open('/home/XXXXX/do.txt','r')
    doStr = f.read()
    if (doStr == 'True'):
        return True
    elif (doStr == 'False'):
        return False
    else:
        return True

def main():

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(25, GPIO.OUT)
    global count
    count = 0
    f = open("/home/XXXXX/count.txt","r")
    countstr = f.read()
    try:
        count = int(countstr)
    except:
        count = 0

    pin = 24
    flg = False

    #start_time = time.time() - start_time

    GPIO.setup(pin, GPIO.IN)
    #GPIO.add_event_detect(pin, GPIO.RISING, callback=callBackRising,bouncetime=100)  
    #GPIO.add_event_detect(pin, GPIO.FALLING, callback=callBackFalling, bouncetime=150)
    GPIO.add_event_detect(pin, GPIO.BOTH, callback=callBackRising, bouncetime=200)

    DoFlg = True
    count_try = 0
    try:
        while DoFlg:
            DoFlg = read_do
            sleep(1)

        finallizeFlg = False;
        c_socket.close()
        GPIO.cleanup()

    except KeyboardInterrupt:
        print("end cleanup")
        GPIO.cleanup()

if __name__ == '__main__':
main()

 

***********ここまでがカウンター**************************************************

 

次は通信プログラムです。


import struct
import time
from time import sleep
import socket
import sys
import signal
import os


HOSTNAME = "192.168.30.131"
PORT = 8600
INTERVAL = 3
RETRYTIMES = 1

global c_socket
def write_count(count):
f = open('/home/shared/tp-1/count.txt' ,'w')
f.write(str(count))
f.close()

def read_do():
    f = open('/home/shared/tp-1/do.txt','r')
    doStr = f.read()
    if (doStr == 'True'):
        return True
    elif (doStr == 'False'):
        return False
    else:
        return True
def read_count():
    f = open('/home/shared/tp-1/count.txt','r')
    countStr = f.read()
    try:
        return int(countStr)
    except:
        pass

def SendCount(arg1, arg2):
    try:
        count = read_count()
        c_socket.send(str(count))
    except:
        savelog('exception happend')
        os.system('/home/hsmt_system/XXXXXX/restart.sh &')
        savelog('after sh')
        sys.exit(0)

def savelog(msg):
    f = open('/home/hsmt_system/h_counter/log.txt' ,'a')
    f.write(str(msg) + '\n')
    f.close()

def socket_connect(host, port, interval, retries):
    global c_socket
    c_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    for x in range(retries):
        try:
            c_socket.connect*1
            return c_socket
        except socket.error:
            print "wait"+str(interval)+"s"
            time.sleep(interval)

    c_socket.close()
    return None

def main():
    passFlg = False
    c_socket = socket_connect(HOSTNAME,PORT,INTERVAL,RETRYTIMES)

    while c_socket is None:
        c_socket = socket_connect(HOSTNAME,PORT,INTERVAL,RETRYTIMES)

    if c_socket is None:
        print "system exit:connection error"
        sys.exit(0)

if __name__ == '__main__':
main()

signal.signal(signal.SIGALRM, SendCount)
signal.setitimer(signal.ITIMER_REAL, 0.2, 0.2)

connectFlg = False

errorFlg = False
while True:
    time.sleep(1)

try:
    c_socket.close()
    GPIO.cleanup()

except KeyboardInterrupt:
    print("end cleanup")
    c_socket.close()

 

*************ここまでが通信プログラム**********************************

 

最後に、再起動用のシェルスクリプトです。

 

#!/bin/sh

python /home/xxxx.py

*1:host, port