我有一个使用socket
和SocketServer
的python2程序。它基本上由一些可以相互连接的客户端组成。每个客户端也有自己的Thread
,它使用threading.Thread
实现并以daemon
模式运行。现在我的问题是,当我调用sys.exit()
时,程序不会退出。我也会(尝试)在sys.exit()
调用之前关闭所有打开的套接字。我也在程序中使用socket.makefile()
,但是,在我读完所有已打开的文件之后,我会立即调用close
。如果sys.exit()
没有退出,可能是什么原因?
这是代码,应用程序应该代表节点图,
如果我们在第一个节点上用第二个节点的地址调用initiateConnection
,每个节点将包含一个Edge到另一个节点。由于边缘是无向的,我希望套接字的两边都由相同的{{1}处理请参阅上面的注释RequestHandler
。
Client.initiateConnection
UPDATE :我已经确定了(相当明显的)问题,句柄方法永远不会退出循环,因为节点总是应该连接,并等待彼此的请求。但我不能检查程序终止,因为它在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)
调用之前卡住了。我该如何解决?
答案 0 :(得分:0)
当所有线程退出时,python程序结束。我认为你的线程函数没有返回,这意味着即使你调用exit(),程序也会等待它们返回。
如果是这种情况(我真的认为是这样),那么一个简单的解决方案就是拥有一个全局'running'标志= True:
running = True
并在每个线程内部创建一个循环,在运行之前检查此标志:
#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
希望有所帮助
答案 1 :(得分:0)
由于RequestHandler.handle
在无限循环中运行,并等待来自另一方的请求,反之亦然,我们必须在主进程退出时终止它。密钥在SocketServer.ThreadingMixin.daemon_threads
必须是设置为true,以便最终运行handle方法的创建线程将在退出时终止。