Python套接字OSError:[Errno 22]关闭时参数无效

时间:2017-05-08 20:59:28

标签: python sockets

当客户发送"停止"时,我正努力优雅地关闭脚本。命令。

在编写脚本时,它实际上会以下列错误退出:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.5/threading.py", line 862, in run
    self._target(*self._args, **self._kwargs)
  File "server.py", line 248, in start_server
    conn, addr = soc.accept()
  File "/usr/lib/python3.5/socket.py", line 195, in accept
    fd, addr = self._accept()
OSError: [Errno 22] Invalid argument

有什么建议吗?

#!/usr/bin/python3

#################################################################################
#  BLE PRESENCE FOR DOMOTICZ                                                    #
#                                                                               #
#  AUTHOR: MARCO BAGLIVO (ITALY) (https://github.com/mydomo)                    #
#                                                                               #
#################################################################################
# BLE_SCAN LIBRARY IS A FORK OF https://github.com/flyinactor91/RasPi-iBeacons  #
#################################################################################

#################################################################################
# INSTALL REQUIREMENTS ON UBUNTU SERVER 16.04:                                  #
#                                                                               #
# sudo apt-get install -y libbluetooth-dev bluez                                #
# sudo apt-get install python-dev python3-dev python3-setuptools python3-pip    #
# sudo pip3 install pybluez                                                     #
#                                                                               #
#################################################################################

import socket
from lib import ble_scan
from threading import Thread
import sys
import os
import time
import bluetooth._bluetooth as bluez
import signal
import subprocess
from collections import OrderedDict

##########- CONFIGURE SCRIPT -##########
socket_ip = '0.0.0.0'
socket_port = 12345
min_inval_between_batt_level_readings = 3600

##########- CONFIGURE TRANSLATIONS -##########
lang_SCAN_STOPPED = 'Scanning stopped by other function'
lang_READING_LOCK = 'Reading in progress...'
lang_READING_START = 'Reading started'


##########- START VARIABLE INITIALIZATION -##########
mode = ''
beacons_detected = ''
batt_lev_detected = ''
scan_beacon_data = True
ble_value = ''
devices_to_analize = {}
batt_lev_detected = {}
read_value_lock = False
##########- END VARIABLE INITIALIZATION -##########

##########- START FUNCTION THAT HANDLE CLIENT INPUT -##########

def socket_input_process(input_string):
    global mode
    global devices_to_analize
    global lang_SCAN_STOPPED
    global lang_READING_LOCK
    global lang_READING_START

    ###- TRANSMIT BEACON DATA -###
    # check if client requested "beacon_data"
    if input_string == 'beacon_data':
        # if beacon scanning function has being stopped in order to process one other request (ex.: battery level) warn the client
        if scan_beacon_data == False:
            return str(lang_SCAN_STOPPED)

        # if beacon scanning function is active send the data to the client
        if scan_beacon_data == True:
            # set operative mode to beacon_data
            mode = 'beacon_data'
            # return beacons_detected ordered by timestamp ASC (tnx to: JkShaw - http://stackoverflow.com/questions/43715921/python3-ordering-a-complex-dict)
            # return "just" the last 300 results to prevent the end of the socket buffer (each beacon data is about 45 bytes)
            return str(sorted(beacons_detected.items(), key=lambda x: x[1][1], reverse=True)[:300])


    ###- TRANSMIT BATTERY LEVEL -###
    # check if the request start with battery_level:
    if input_string.startswith('battery_level:'):
        # trim "battery_level:" from the request
        string_devices_to_analize = input_string.replace("battery_level: ", "")
        # split each MAC address in a list in order to be processed
        devices_to_analize = string_devices_to_analize.split(',')
        # set operative mode to battery_level
        mode = 'battery_level'

        # if the reading has already requested and there is no result ask to wait
        if not batt_lev_detected and read_value_lock == True:
            return str(lang_READING_LOCK)

        # if the reading is requested for the first time start say that will start
        elif not batt_lev_detected and read_value_lock == False:
            return str(lang_READING_START)

        # if is present a battery data send it
        else:
            return str(batt_lev_detected)

    ###- STOP RUNNING SERVICES -###
    if input_string == 'stop':
        killer.kill_now = True
        print ('service stopping')
        return str('Service stopping')
##########- END FUNCTION THAT HANDLE CLIENT INPUT -##########

##########- START FUNCTION THAT HANDLE SOCKET'S TRANSMISSION -##########
def client_thread(conn, ip, port, MAX_BUFFER_SIZE = 32768):
    # the input is in bytes, so decode it
    input_from_client_bytes = conn.recv(MAX_BUFFER_SIZE)

    # MAX_BUFFER_SIZE is how big the message can be
    # this is test if it's too big
    siz = sys.getsizeof(input_from_client_bytes)
    if  siz >= MAX_BUFFER_SIZE:
        print("The length of input is probably too long: {}".format(siz))

    # decode input and strip the end of line
    input_from_client = input_from_client_bytes.decode("utf8").rstrip()

    res = socket_input_process(input_from_client)
    #print("Result of processing {} is: {}".format(input_from_client, res))

    vysl = res.encode("utf8")  # encode the result string
    conn.sendall(vysl)  # send it to client
    conn.close()  # close connection
##########- END FUNCTION THAT HANDLE SOCKET'S TRANSMISSION -##########

def usb_dongle_reset():
    process0 = subprocess.Popen("sudo hciconfig hci0 down", stdout=subprocess.PIPE, shell=True)
    process0.communicate()
    process1 = subprocess.Popen("sudo hciconfig hci0 reset", stdout=subprocess.PIPE, shell=True)
    process1.communicate()
    process2 = subprocess.Popen("sudo /etc/init.d/bluetooth restart", stdout=subprocess.PIPE, shell=True)
    process2.communicate()
    process3 = subprocess.Popen("sudo hciconfig hci0 up", stdout=subprocess.PIPE, shell=True)
    process3.communicate()

def ble_scanner():
    global beacons_detected
    dev_id = 0
    usb_dongle_reset()

    try:
        sock = bluez.hci_open_dev(dev_id)
        #print ("ble thread started")
    except:
        print ("error accessing bluetooth device... restart in progress!")
        usb_dongle_reset()

    ble_scan.hci_le_set_scan_parameters(sock)
    ble_scan.hci_enable_le_scan(sock)
    beacons_detected = {}
    while (scan_beacon_data == True) and (not killer.kill_now):
        try:
            returnedList = ble_scan.parse_events(sock, 25)
            for beacon in returnedList:
                MAC, RSSI, LASTSEEN = beacon.split(',')
                beacons_detected[MAC] = [RSSI,LASTSEEN]
            time.sleep(1)
        except:
            print ("failed restarting device... let's try again!")
            usb_dongle_reset()         
            dev_id = 0
            sock = bluez.hci_open_dev(dev_id)
            ble_scan.hci_le_set_scan_parameters(sock)
            ble_scan.hci_enable_le_scan(sock)
            time.sleep(1)

def read_battery_level():
    global scan_beacon_data
    global mode
    global batt_lev_detected
    global read_value_lock
    global min_inval_between_batt_level_readings
    uuid_to_check = '0x2a19'
    time_difference = 0
    while (not killer.kill_now):
        if mode == 'battery_level' and read_value_lock == False:
            read_value_lock = True
            #print ("Dispositivi da analizzare: " + str(devices_to_analize))
            for device in devices_to_analize:
                device_to_connect = device
                #print ("Analizzo dispositivo: " + str(device))
                # i'm reading the value stored
                battery_level_moderator =  str(batt_lev_detected.get(device, "Never"))
                # cleaning the value stored
                cleaned_battery_level_moderator = str(battery_level_moderator.replace("[", "").replace("]", "").replace(" ", "").replace("'", ""))
                # assign the battery level and the timestamp to different variables
                if cleaned_battery_level_moderator != "Never":
                    stored_batterylevel, stored_timestamp = cleaned_battery_level_moderator.split(',')
                    time_difference = int(time.time()) - int(stored_timestamp)

                if (int(min_inval_between_batt_level_readings) <= int(time_difference)) or (str(cleaned_battery_level_moderator) == "Never") or (str(stored_batterylevel) == '255'):
                    scan_beacon_data = False
                    usb_dongle_reset()
                    #PUT HERE THE CODE TO READ THE BATTERY LEVEL
                    try:
                        handle_ble = os.popen("sudo hcitool lecc --random " + device_to_connect + " | awk '{print $3}'").read()
                        handle_ble_connect = os.popen("sudo hcitool ledc " + handle_ble).read()
                        #ble_value = int(os.popen("sudo gatttool -t random --char-read --uuid " + uuid_to_check + " -b " + device_to_connect + " | awk '{print $4}'").read() ,16)
                        ble_value = os.popen("sudo gatttool -t random --char-read --uuid " + uuid_to_check + " -b " + device_to_connect + " | awk '{print $4}'").read()
                    except:
                        ble_value = 'nd'

                    if ble_value != '':
                        ble_value = int(ble_value ,16)

                    if ble_value == '':
                        ble_value = '255'    
                    time_checked = str(int(time.time()))
                    batt_lev_detected[device] = [ble_value,time_checked]
                    read_value_lock = False
                    #print (batt_lev_detected)

            #AS SOON AS IT FINISH RESTART THE scan_beacon_data PROCESS
            scan_beacon_data = True
            mode = 'beacon_data'
            Thread(target=ble_scanner).start()
        time.sleep(1)


def start_server():
    global soc
    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # this is for easy starting/killing the app
    soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    #print('Socket created')
    try:
        soc.bind((socket_ip, socket_port))
    #    print('Socket bind complete')
    except socket.error as msg:
    #    print('Bind failed. Error : ' + str(sys.exc_info()))
        sys.exit()


    #Start listening on socket
    soc.listen(10)
    #print('Socket now listening')

    # for handling task in separate jobs we need threading
    #from threading import Thread

    # this will make an infinite loop needed for 
    # not reseting server for every client
    while (not killer.kill_now):
        conn, addr = soc.accept()
        ip, port = str(addr[0]), str(addr[1])
        #print('Accepting connection from ' + ip + ':' + port)
        try:
            Thread(target=client_thread, args=(conn, ip, port)).start()
        except:
            print("Terible error!")
            import traceback
            traceback.print_exc()
    soc.close()

def kill_socket():
    global soc
    global kill_now
    kill_socket_switch = False
    while (not kill_socket_switch):
        if killer.kill_now:
            print ("KILL_SOCKET PROVA A CHIUDERE IL SOCKET")
            time.sleep(1)
            soc.shutdown(socket.SHUT_RDWR)
            soc.close()
            kill_socket_switch = True
        time.sleep(1)

### MAIN PROGRAM ###
class GracefulKiller:
  kill_now = False
  def __init__(self):
    signal.signal(signal.SIGINT, self.exit_gracefully)
    signal.signal(signal.SIGTERM, self.exit_gracefully)

  def exit_gracefully(self,signum, frame):
    global soc
    self.kill_now = True
    print ('Program stopping...')

if __name__ == '__main__':
    killer = GracefulKiller()
    Thread(target=start_server).start()
    Thread(target=ble_scanner).start()
    Thread(target=read_battery_level).start()
    Thread(target=kill_socket).start()
#  print ("End of the program. I was killed gracefully :)")

0 个答案:

没有答案