简体   繁体   中英

sys.exit() not exiting in python

I have a python2 program which uses socket and SocketServer . it basically consists of some clients, that can connect with each other.Each Client also has their own Thread which is implemented using threading.Thread and run in daemon mode. Now my problem is that when i call sys.exit() the program doesn't exit.I also (try to) close all open sockets before sys.exit() call.I also use socket.makefile() in the program, however I call close on all of the opened files right after I read from them.What could be the potential causes if sys.exit() not exiting?

Here's the code, the application is supposed to represent a graph of nodes, each node will contain an Edge to another node if we call initiateConnection on the first node with the address of the second one.Since the Edges are undirected I want both sides of the socket to be handled by the same RequestHandler .See notes above Client.initiateConnection .

import socket
import SocketServer
import select
import sys
import threading

class Client(SocketServer.ThreadingTCPServer):

    """Attributes:
    neighbours: connections to neighbours
    n_addresses: addresses of Neighbours
    requests: Number of Requests Sent
    processed_requests:{}
    id: this client's id
    """

    def __init__(self, server_address, RequestHandlerClass, id):
        self.neighbours = []
        self.n_addresses = []
        self.requests = 0
        self.processed_requests = {}
        self.id = id
        SocketServer.ThreadingTCPServer.__init__(self, server_address, RequestHandlerClass)

    def initiateConnection(self, address):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(address)
        self.neighbours.append(s)
        self.n_addresses.append(s.getpeername())
        self.addConnection(s, address)
        # check if the given port, and the connected one match
        if address[1] != s.getpeername()[1]:
            raise Exception(address, s.getpeername())

    """ this method is based on the _handle_request_no_block method on the base server
    we will add the connection created by this node i.e: this node is the client for that
    particular connection, to the list of connections handled by this server, i.e: view it as a server connection
    """
    #This method is supposed to add the request first instantiated by
    # the Client instance itself, to the requests the ThreadingTCPServer manages (creates a seperate thread for it and etc.)
    # Maybe there's something else I have to do, so that the ThreadingTCPServer closes this connection properly?
    def addConnection(self, request, address):
        if self.verify_request(request, address):
            try:
                self.process_request(request, address)
            except:
                self.handle_error(request, address)
                self.shutdown_request(request)

    def addNeighbour(self, s):
        self.neighbours.append(s)
        self.n_addresses.append(s.getpeername())

    def server_close(self):
        print("{}: closing neighbours".format(self.id))
        for c in self.neighbours:
            print("{}: closing {}".format(c.getpeername()))
            c.close()
        print("{}: closed all neighbours".format(self.id))
        SocketServer.ThreadingTCPServer.server_close(self)


class RequestHandler(SocketServer.StreamRequestHandler):

    GET_NEIGHBOURS="1"
    EOR="EOR"
    # the below function means someone is trying to initiate
    # connection, since it will be handled in it's own thread
    # we will initiate a loop and wait for a request.
    def handle(self):
        self.server.addNeighbour(self.request)
        while True:
            lines = []
            select.select([self.rfile], [], [])
            print("{}: got request from {}".format(self.server.id, self.request.getpeername()))
            while True:
                line = self.rfile.readline().strip()
                print("line read:\n{}".format(line))
                if line == RequestHandler.EOR:
                    break
                elif not bool(line):
                    continue
                lines.append(line)
            print("{}: all request lines read:\n{}".format(self.server.id, lines))
            # we have a complete request now process it
            if lines[1] == self.GET_NEIGHBOURS:
                print("{}: request was of type    get_neighbours".format(self.server.id))
                data = self.processNeighbours(lines)
                self.request.sendall("{}\n".format(data))
                print("{}: data sent to {}".format(self.server.id, self.request.getpeername()))

class UnknownRequestCode(Exception): pass

if __name__ == '__main__':

    def output(s):
        print(s)
    def getLine():
        return sys.stdin.readline()

    address = ('', 0)
    clients = {}
    addresses = {}
    while True:
        print("commands:\nclose: exit\nnew: make a new client, will prompt for a client id\nshow: show a clients neighbours, will prompt for a client's id\nconnect: will connect a client to another one, will prompt for the ids")
        i = getLine().strip()
        if i == "close":
            for c in clients.values():
                c.shutdown()
            print("everything shut down")
            sys.exit()
        if i == "new":
            i = getLine(). strip()
            client = Client(address, RequestHandler, i)
            clients[i] = client
            a = client.server_address
            addresses[i] = a
            output(a)
            t = threading.Thread(target=client.serve_forever)
            t.daemon = True
            t.start()
        elif i == "show":
            i = getLine().strip()
            c = clients[i]
            o = c.startSearch()
            #output(o)       
        elif i == "connect":
            i = getLine().strip()
            c = clients[i]
            i = getLine().strip()
            a = addresses[i]
            print("{}".format(a))
            c.initiateConnection(a)

UPDATE : I have identified the (rather obvious) problem, the handle method never exits the loop since the nodes are always supposed to get connected, and wait for each other's request.But I can not check program termination since it gets stuck before the select.select call.How can I fix that?

a python program ends when all threads exit. i think your thread functions do not return which means the program will wait for them to return even if you call exit().

if that is the case (and i really think it is), then a simple solution is to have a global 'running' flag = True:

running = True

and inside each thread, you create a loop that checks this flag before running:

#thread function
def thread_function ():
    #loop checks the flag
    while running:
        pass    #write loop code here
    #if running turns to false, then you will be here
    pass    #write clean up code here

hope it helps

由于RequestHandler.handle在无限循环中运行,并等待另一端的请求,反之亦然,因此我们必须在主进程退出时终止它。键位于SocketServer.ThreadingMixin.daemon_threads ,必须将其设置为true,因此最终将运行handle方法的已创建线程将在退出时终止。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM