Ctrl + C не останавливает программу - PullRequest
0 голосов
/ 02 ноября 2018

У меня есть приемник, который прослушивает как TCP, так и UDP пакеты. У меня также есть функция foo (), которая запускается одновременно, печатает текущее время и отправляет пакет UDP каждые 5 секунд.

Проблема в том, что когда я нажимаю кнопки 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 в первый раз?

Ответы [ 2 ]

0 голосов
/ 04 ноября 2018

Как убить программу, нажав Ctrl + C в первый раз?

Самый простой способ - удалить обработчик сигнала и позволить процессу немедленно завершиться на SIGINT. Поместите это в начале вашего кода:

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

Другой вариант заключается в том, что вы можете нажать Ctrl + \, чтобы отправить SIGQUIT вместо SIGINT. Это работает без изменений кода в большинстве программ ... но может генерировать дампы ядра.

Обратите внимание, что, выполнив одно из вышеперечисленных действий, вы лишаете программу возможности выполнять постепенное отключение. Но это может быть не важно для большинства программ, так как операционная система очищает неиспользуемые ресурсы после завершения.

0 голосов
/ 02 ноября 2018

Когда вы нажимаете ctrl + c в первый раз, он завершает поток, в котором вы находитесь в данный момент, но не завершает основной поток, в котором выполняется остальная часть программы. Когда вы делаете это во второй раз, вы завершаете основной поток

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...