Ctrl + C不会停止程序

时间:2018-11-02 18:39:13

标签: python terminate

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

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

我按照本post中的建议增加了加薪。在上一个问题中它对我有用,但是在我添加了其他部分之后,它不再起作用。

代码如下:

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怎么杀死程序?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

  

如何通过第一次按public class ReadTxtFileResult { public Stack Stack { get; set; } public DataTable DataTable { get; set; } } 来终止程序?

一种简单的方法是删除信号处理程序,并让进程立即在SIGINT上终止。将其放在代码开头附近:

public ReadTxtFileResult ReadTxtFile(string Flepath)
{
    Stack stk = new Stack();
    DataTable dt = new DataTable();
    return new ReadTxtFileResult
    {
        Stack = stk,
        DataTable = dt
    }
}

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

请注意,通过执行上述任一操作,您将抢夺该程序执行正常关机的能力。但这对于大多数程序而言可能并不重要,因为操作系统将在终止时清除未使用的资源。