Ctrl + C 不会停止程序

Ctrl + C is not stopping the program

我有一个正在侦听 TCP 和 UDP 数据包的接收器。我还有一个同时运行并打印当前时间并每 5 秒发送一个 UDP 数据包的 foo() def。

问题是当我按 Ctrl + C 按钮终止程序时,第一次没有终止,我应该至少按这些按钮两次。

我按照 中的建议添加了加注。上一个问题对我有用,但是我添加了其他部分后,它又没有用了。

代码如下:

from __future__ import print_function
from select import select
import socket
from struct import pack
from struct import unpack
from collections import deque

host = '10.0.0.2'
port = 5005
backlog = 5
BUFSIZE = 4096
q = deque()


import time, threading
def foo():
    try:
        print(time.ctime())
        threading.Timer(5, foo).start()
    except KeyboardInterrupt:
        print('\nClosing')
        raise


class Receiver:
    ''' Buffer binary data from socket conn '''
    def __init__(self, conn):
        self.conn = conn
        self.buff = bytearray()

    def get(self, size):
        ''' Get size bytes from the buffer, reading
            from conn when necessary 
        '''
        while len(self.buff) < size:
            data = self.conn.recv(BUFSIZE)
            if not data:
                break
            self.buff.extend(data)
        # Extract the desired bytes
        result = self.buff[:size]
        # and remove them from the buffer
        del self.buff[:size]
        return bytes(result)

    def save(self, fname):
        ''' Save the remaining bytes to file fname '''
        with open(fname, 'wb') as f:
            if self.buff:
                f.write(bytes(self.buff))
            while True:
                data = self.conn.recv(BUFSIZE)
                if not data:
                    break
                f.write(data)

def send(sock2, data2):
    while data2:
        sent = sock2.send(data2)
        data2 = data2[sent:]

def send_file(ipToTransfer, fname):
    with open(fname, 'rb') as f:
        sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            sock2.connect((ipToTransfer, 5005))
        except socket.error as err:
            print(err, ipToTransfer, 5005)
            sock2.close()
            return

        # Send the file name length & the filename itself in one packet          
        send(sock2, pack('B', len(fname)) + fname.encode())
        while True:
            data2 = f.read(BUFSIZE)
            if not data2:
                break
            send(sock2, data2)

    sock2.close()

def read_tcp(s):
    conn, addr = s.accept()
    print('Connected with', *addr)
    # Create a buffer for this connection
    receiver = Receiver(conn)
    # Get the length of the file name
    name_size = unpack('B', receiver.get(1))[0]
    name = receiver.get(name_size).decode()
    q.append(name)
    print('name', name)
    # Save the file
    receiver.save(name)
    conn.close()
    print('saved\n')

def read_udp(s):
    data,addr = s.recvfrom(1024)
    print("received message:", data)

def run():

    # create tcp socket
    tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    try:
        tcp.bind((host,port))
    except socket.error as err:
        print('Bind failed', err)
        return
    tcp.listen(1)

    # create udp socket
    udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
    udp.bind((host,port))

    print('***Socket now listening at***:', host, port)
    input = [tcp,udp]

    try:
        while True:
            inputready,outputready,exceptready = select(input,[],[])

            for s in inputready:
                if s == tcp:
                    read_tcp(s)
                elif s == udp:
                    read_udp(s)
                else:
                    print("unknown socket:", s)

    # Hit Break / Ctrl-C to exit
    except KeyboardInterrupt:
        print('\nClosing')
        raise

    tcp.close()
    udp.close()

if __name__ == '__main__':
    foo()
    run()

第一次按Ctrl + C,程序没有终止,需要按第二次。怎么了?如何在第一次按 Ctrl + C 时终止程序?

当您第一次按下 ctrl + c 时,它会终止您当前所在的线程,但不会终止程序其余部分所在的主线程 运行。当你第二次这样做时,你将终止主线程

How can i kill the program by pressing Ctrl + C for the first time?

一个简单的方法是删除信号处理程序,让进程在收到 SIGINT 时立即死亡。将其放在代码的开头附近:

import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

另一种选择是您可以按 Ctrl + \ 发送 SIGQUIT 而不是 SIGINT。在大多数程序中无需更改代码即可工作...但可能会生成核心转储。

请注意,执行上述任一操作都会剥夺程序正常关机的能力。但这对大多数程序来说可能并不重要,因为操作系统会在终止时清理未使用的资源。