客户端断开后重新启动套接字连接

时间:2012-08-28 16:58:44

标签: python sockets mit-scratch

我有这个代码,它在启用远程传感器连接的情况下侦听/发送给Scratch程序(例如,通过端口42001在127.0.0.1上进行通信)

# This code is copyright Simon Walters under GPL v2
# This code is derived from scratch_handler by Thomas Preston
# Version 5dev 11Aug08 Much better looping supplied by Stein @soilandreyes
# and someone else @MCrRaspJam who've name I've forgotton!
# Version 6dev - Moved Allon/AllOff to be processed before single pins :)
# Vesion 7dev - start to tidy up changes
# Vesion 8dev - use gpio-output system and broadcast allon, 1on system
# V0.1 - change to 6 out 2 in and sanitise the code
# V0.2 -

from array import *
import threading
import socket
import time
import sys
import struct

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11,GPIO.OUT)
GPIO.setup(12,GPIO.OUT)
GPIO.setup(13,GPIO.OUT)
GPIO.setup(15,GPIO.OUT)
GPIO.setup(16,GPIO.OUT)
GPIO.setup(18,GPIO.OUT)
GPIO.setup(22,GPIO.IN,pull_up_down=GPIO.PUD_UP)
GPIO.setup(7,GPIO.IN,pull_up_down=GPIO.PUD_UP)


'''
from Tkinter import Tk
from tkSimpleDialog import askstring
root = Tk()
root.withdraw()
'''

PORT = 42001
DEFAULT_HOST = '127.0.0.1'
#HOST = askstring('Scratch Connector', 'IP:')
BUFFER_SIZE = 240 #used to be 100
SOCKET_TIMEOUT = 1

SCRATCH_SENSOR_NAME_INPUT = (
    'gpio-input0',
    'gpio-input1'
)

SCRATCH_SENSOR_NAME_OUTPUT = (
    'gpio-output0',
    'gpio-output1',
    'gpio-output2',
    'gpio-output3',
    'gpio-output4',
    'gpio-output5'
)

SCRATCH_BROADCAST_NAME_OUTPUT = (
    '1on','1off','2on','2off','3on','3off','4on','4off','5on','5off','6on','6off'
)

#Map gpio to real connector P1 Pins
GPIO_PINS = array('i',[11,12,13,15,16,18,22,7])
GPIO_PIN_OUTPUT = array('i')
GPIO_PIN_INPUT = array('i')
print "Output Pins are:"
for i in range(0,len(SCRATCH_SENSOR_NAME_OUTPUT)):
    print GPIO_PINS[i]
    GPIO_PIN_OUTPUT.append(GPIO_PINS[i])
print "Input Pins are:" 
for i in range(len(SCRATCH_SENSOR_NAME_OUTPUT),8):
    print GPIO_PINS[i]
    GPIO_PIN_INPUT.append(GPIO_PINS[i])

class ScratchSender(threading.Thread):
     #Not needed as its a Listening issue 
     ...   

class ScratchListener(threading.Thread):
    def __init__(self, socket):
        threading.Thread.__init__(self)
        self.scratch_socket = socket
        self._stop = threading.Event()

    def stop(self):
        self._stop.set()

    def stopped(self):
        return self._stop.isSet()

    def physical_pin_update(self, pin_index, value):
        physical_pin = GPIO_PIN_OUTPUT[pin_index]
        print 'setting GPIO %d (physical pin %d) to %d' % (pin_index,physical_pin,value)
        GPIO.output(physical_pin, value)

    def run(self):
        #This is main listening routine
        while not self.stopped():
            #time.sleep(0.1) # be kind to cpu
            try:
                data = self.scratch_socket.recv(BUFFER_SIZE)
                dataraw = data[4:].lower()
                print 'Length: %d, Data: %s' % (len(dataraw), dataraw)
                if len(dataraw) == 0:
                    #This is probably due to client disconnecting
                    #I'd like the program to retry connecting to the client
                    time.sleep(2)
            except socket.timeout:
                print "sockect timeout"
                time.sleep(1)
                continue
            except:
                break

            if 'sensor-update' in dataraw:
                #gloablly set all ports
                if 'gpio-outputall' in dataraw:
                    outputall_pos = dataraw.find('gpio-outputall')
                    sensor_value = dataraw[(outputall_pos+16):].split()
                    #print sensor_value[0]
                    for i in range(len(SCRATCH_SENSOR_NAME_OUTPUT)):
                        self.physical_pin_update(i,int(sensor_value[0]))

                #check for individual port commands
                for i in range(len(SCRATCH_SENSOR_NAME_OUTPUT)):
                    if 'gpio-output'+str(i) in dataraw:
                        #print 'Found '+ 'gpio-output'+str(i)
                        outputall_pos = dataraw.find('gpio-output'+str(i))
                        sensor_value = dataraw[(outputall_pos+14):].split()
                        #print sensor_value[0]
                        self.physical_pin_update(i,int(sensor_value[0]))

                #Use bit pattern to control ports
                if 'gpio-pattern' in dataraw:
                    #print 'Found gpio-outputall'
                    num_of_bits = len(SCRATCH_SENSOR_NAME_OUTPUT)
                    outputall_pos = dataraw.find('gpio-pattern')
                    sensor_value = dataraw[(outputall_pos+14):].split()
                    #print sensor_value[0]
                    bit_pattern = ('0000000000000000'+sensor_value[0])[-num_of_bits:]
                    #print 'bit_pattern %s' % bit_pattern
                    for i in range(len(SCRATCH_SENSOR_NAME_OUTPUT)):
                    #bit_state = ((2**i) & sensor_value) >> i
                    #print 'dummy gpio %d state %d' % (i, bit_state) 
                        physical_pin = GPIO_PIN_OUTPUT[i]
                        if bit_pattern[-(i+1)] == '0':
                            print 'setting GPIO %d (physical pin %d) low' % (i,physical_pin)
                            GPIO.output(physical_pin, 0)
                        else:
                            print 'setting GPIO %d (physical pin %d) high' % (i,physical_pin)
                            GPIO.output(physical_pin, 1)

            elif 'broadcast' in dataraw:
                #print 'received broadcast: %s' % data
                if 'allon' in dataraw:
                    for i in range(len(SCRATCH_SENSOR_NAME_OUTPUT)):
                        self.physical_pin_update(i,1)
                if 'alloff' in dataraw:
                    for i in range(len(SCRATCH_SENSOR_NAME_OUTPUT)):
                        self.physical_pin_update(i,0)
                for i in range(len(SCRATCH_SENSOR_NAME_OUTPUT)):
                    #check_broadcast = str(i) + 'on'
                    #print check_broadcast
                    if str(i+1)+'on' in dataraw:
                        self.physical_pin_update(i,1)
                    if str(i+1)+'off' in dataraw:
                        self.physical_pin_update(i,0)
                    if 'pin' + str(GPIO_PIN_OUTPUT[i])+'on' in dataraw:
                        GPIO.output(physical_pin, 1)
                    if 'pin' + str(GPIO_PIN_OUTPUT[i])+'off' in dataraw:
                        GPIO.output(physical_pin, 0)

            elif 'stop handler' in dataraw:
                cleanup_threads((listener, sender))
                sys.exit()

            else:
                print 'received something: %s' % dataraw


def create_socket(host, port):
    while True:
        try:
            print 'Trying'
            scratch_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            scratch_sock.connect((host, port))
            break
        except socket.error:
            print "There was an error connecting to Scratch!"
            print "I couldn't find a Mesh session at host: %s, port: %s" % (host, port) 
            time.sleep(3)
            #sys.exit(1)

    return scratch_sock

def cleanup_threads(threads):
    for thread in threads:
        thread.stop()

    for thread in threads:
        thread.join()

if __name__ == '__main__':
    if len(sys.argv) > 1:
        host = sys.argv[1]
    else:
        host = DEFAULT_HOST

    # open the socket
    print 'Connecting...' ,
    the_socket = create_socket(host, PORT)
    print 'Connected!'

    the_socket.settimeout(SOCKET_TIMEOUT)


    listener = ScratchListener(the_socket)
    sender = ScratchSender(the_socket)
    listener.start()
    sender.start()
    # wait for ctrl+c
    try:
        while True:
            time.sleep(0.5)            
    except KeyboardInterrupt:
        cleanup_threads((listener, sender))
        sys.exit()

我遇到的问题是这部分代码

    def run(self):
        #This is main listening routine
        while not self.stopped():
            #time.sleep(0.1) # be kind to cpu
            try:
                data = self.scratch_socket.recv(BUFFER_SIZE)
                dataraw = data[4:].lower()
                print 'Length: %d, Data: %s' % (len(dataraw), dataraw)
                if len(dataraw) == 0:
                    #This is probably due to client disconnecting
                    #I'd like the program to retry connecting to the client
                    time.sleep(2)
            except socket.timeout:
                print "sockect timeout"
                time.sleep(1)
                continue
            except:
                break

如果客户端断开连接,例如Scratch已关闭,我需要此程序基本上重新开始寻找连接并等待Scratch重新连接。 我可以就如何实现这一点提出一些建议,因为我是一个蟒蛇新手 问候 西蒙

我的解决方案是使用全局变量并更改主循环结构

        if len(dataraw) == 0:
            #This is probably due to client disconnecting
            #I'd like the program to retry connecting to the client
            #tell outer loop that Scratch has disconnected
            if cycle_trace == 'running':
                cycle_trace = 'disconnected'
                break

用于突破循环和

cycle_trace = 'start'
while True:

    if (cycle_trace == 'disconnected'):
        print "Scratch disconnected"
        cleanup_threads((listener, sender))
        time.sleep(1)
        cycle_trace = 'start'

    if (cycle_trace == 'start'):
        # open the socket
        print 'Starting to connect...' ,
        the_socket = create_socket(host, PORT)
        print 'Connected!'
        the_socket.settimeout(SOCKET_TIMEOUT)
        listener = ScratchListener(the_socket)
        sender = ScratchSender(the_socket)
        cycle_trace = 'running'
        print "Running...."
        listener.start()
        sender.start()

    # wait for ctrl+c
    try:
        #just pause
        time.sleep(0.5)
    except KeyboardInterrupt:
        cleanup_threads((listener,sender))
        sys.exit()

这是我的主要外循环 似乎工作:))

0 个答案:

没有答案