Почему KeyboardInterrupt не работает в многопоточности - PullRequest
0 голосов
/ 25 апреля 2020

На самом деле я пытаюсь написать Python код, в котором чтение / запись из сокета обрабатывается в другом потоке - цель состоит в том, чтобы записать 5 раз в сокет, а затем прочитать то же самое, затем снова записать и прочитать и так далее - до сих пор я еще не достиг цели, но столкнулся с проблемой при ее разработке:

KeyboardInterrupt в моем коде не работает - я не уверен, почему?

import socket
from threading import Thread
from time import sleep
import sys

exit = False

def rxThread(rxSocket):
    global exit    
    while not exit:
        try:
            data,addr = rxSocket.recvfrom(1024) 
            print (data)
        except socket.error:
            pass
        except KeyboardInterrupt:
            exit = True
            print ("Received Ctrl+C... initiating exit")

def txThread(portNum):
    global exit

def main():    
    global exit
    UDP_IP="100.108.9.105"
    UDP_PORT=1000      
    sleep(.1)

    #Generate a transmit socket object
    txSocket = sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    #Do not block when looking for received data (see above note)
    txSocket.setblocking(0) 
    udpRxThreadHandle = Thread(target=rxThread,args=(txSocket,))    
    udpRxThreadHandle.start()
    try:
        string="30 29 02 01 00 04 06 00"  
        arr = string.split(" ")
        barr = bytearray()
        for i in range(len(arr)):
            barr.append(int(arr[i], 16))
        #Transmit data to the local server on the agreed-upon port
        for i in range(1,2,1):
            sock.sendto(barr,(UDP_IP,UDP_PORT))
    except socket.error:    
        #If no data is received you end up here, but you can ignore
        #the error and continue
        pass   
    except KeyboardInterrupt:
        exit = True
        udpRxThreadHandle.join()
        print ("Received Ctrl+C... initiating exit")
    sleep(.1)
    udpRxThreadHandle.join()
    return

if __name__=="__main__":
    main()   

Я не уверен, как достичь цели?

1 Ответ

0 голосов
/ 25 апреля 2020

В python только основной поток получает сигнал. Если вы используете его, чтобы закрыть сокет дейтаграммы, recvfrom поднимет OSError, и вы сможете выйти из потока. Скорее всего, вы можете полностью удалить переменную exit. Как минимум, измените его имя, чтобы оно не скрывало встроенную функцию exit().

import socket
from threading import Thread
from time import sleep
import sys

# todo: if this is just to handle the keyboardinterrupt case, remove
exit = False

def rxThread(rxSocket):
    global exit    
    while not exit:
        try:
            data,addr = rxSocket.recvfrom(1024) 
            print (data)
        except socket.error:
            pass
        except OSError:
            exit = True
            print ("Socket closed... initiating exit")

def txThread(portNum):
    global exit

def main():    
    global exit
    UDP_IP="100.108.9.105"
    UDP_PORT=1000      
    sleep(.1)

    #Generate a transmit socket object
    txSocket = sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    #Do not block when looking for received data (see above note)
    txSocket.setblocking(0) 
    udpRxThreadHandle = Thread(target=rxThread,args=(txSocket,))    
    udpRxThreadHandle.start()
    try:
        string="30 29 02 01 00 04 06 00"  
        arr = string.split(" ")
        barr = bytearray()
        for i in range(len(arr)):
            barr.append(int(arr[i], 16))
        #Transmit data to the local server on the agreed-upon port
        for i in range(1,2,1):
            sock.sendto(barr,(UDP_IP,UDP_PORT))
    except socket.error:    
        #If no data is received you end up here, but you can ignore
        #the error and continue
        pass   
    except KeyboardInterrupt:
        exit = True
        sock.close()
        print ("Received Ctrl+C... initiating exit")
    udpRxThreadHandle.join()
    return

if __name__=="__main__":
    main()   
...