停止线程模块python中的服务器程序
我正在用python编写一个简单的信息服务器,它响应3个不同的命令。我必须使用线程模块处理多个客户机,所以任何其他处理多个客户机的方法都不行。每当客户端向服务器发送“EXIT”时,服务器程序都应该停止执行。我想我可以通过关闭处理客户机的线程内的连接和套接字来实现这一点。当我这样做时,服务器只是在收到“退出”后继续运行,当下一个客户端尝试连接时崩溃,出现以下错误:停止线程模块python中的服务器程序,python,multithreading,sockets,Python,Multithreading,Sockets,我正在用python编写一个简单的信息服务器,它响应3个不同的命令。我必须使用线程模块处理多个客户机,所以任何其他处理多个客户机的方法都不行。每当客户端向服务器发送“EXIT”时,服务器程序都应该停止执行。我想我可以通过关闭处理客户机的线程内的连接和套接字来实现这一点。当我这样做时,服务器只是在收到“退出”后继续运行,当下一个客户端尝试连接时崩溃,出现以下错误: Exception in thread Thread-1: Traceback (most recent call last):
Exception in thread Thread-1:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 530, in __bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 483, in run
self.__target(*self.__args, **self.__kwargs)
File "info_mult_thread.py", line 69, in handle_client
s.shutdown(socket.SHUT_RDWR)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 222, in meth
return getattr(self._sock,name)(*args)
error: [Errno 57] Socket is not connected
这是我的密码:
import socket
import time
from threading import Thread
TCP_HOST = 'localhost'
TCP_PORT = 1997
BUFFER_SIZE = 1024
# create socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to the server
s.bind((TCP_HOST, TCP_PORT))
# put socket into server mode, this means listen for incoming connections
s.listen(10)
def handle_client(connection_input, client_address_input):
""" Will handle the requests of the client
:param connection_input: Connection with the client
:param client_address_input: Address of the client
:return: No return value
"""
complete_command = False
command = ""
while True:
# wait 10 seconds for data from client, otherwise disconnect
connection_input.settimeout(10.0)
try:
data = connection_input.recv(BUFFER_SIZE)
except socket.timeout:
# client is idle, close the connection
connection_input.close()
break
else:
# client has closed the connection
if not data:
break
# add the data to the command
command += data
# check whether the command is complete or not
if command.endswith("\n"):
complete_command = True
command = command.rstrip('\r\n')
if complete_command:
# full command entered
if command == 'IP':
# client wants his ip address
client_ip, client_port = client_address_input
connection_input.send(client_ip)
elif command == 'TIME':
# client wants the server-time
connection_input.send(time.ctime())
elif command == 'EXIT':
# stop the program
connection_input.close()
s.shutdown(socket.SHUT_RDWR)
s.close()
else:
# command is not supported
connection_input.send("The command you've entered is not supported")
complete_command = False
command = ""
try:
while True:
# wait for a connection
connection, client_address = s.accept()
# start a thread to handle the client
t = Thread(target=handle_client, args=(connection, client_address))
t.start()
finally:
connection.close()
这有点像黑客,但您可以在调用s.close之前建立到服务器的本地连接,这将保证s.accept立即引发异常:
def handle_client(connection_input, client_address_input):
""" Will handle the requests of the client
:param connection_input: Connection with the client
:param client_address_input: Address of the client
:return: No return value
"""
<snip>
while True:
<snip>
elif command == 'EXIT':
connection_input.close()
# Make a local connection, then close the socket
socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((TCP_HOST, TCP_PORT))
s.close()
break # Break out of the while loop here.
try:
while True:
# this will never block, because of select.select
connection, client_address = s.accept()
# start a thread to handle the client
t = Thread(target=handle_client, args=(connection, client_address))
t.start()
except socket.error:
print("Shutting down")
finally:
connection.close()
使用s.shutdownsocket.Shutrdwr代替s.close。请注意,这将使s.accept抛出一个异常,您可能希望捕获该异常。我已经尝试过了,但服务器仍然不会关闭,我每次都会收到一个属性错误。具体的属性错误是什么?您的编辑似乎删除了原始问题的回溯;它没有添加任何新信息。我看我把编辑搞砸了。很抱歉。现在应该可以了,您正在使用名为socket的变量屏蔽套接字模块。您的原始代码没有这样做-您使用了变量s。只要恢复使用s,它就可以正常工作。是的,我知道如何使用select模块处理多个客户端。但是select只是半并发的,我的任务特别声明我必须使用线程模块。对不起,如果我的问题不清楚,我现在已经改了。不过我真的很感谢你的努力。不过,这个解决方案仍然在每个连接中使用线程。唯一的区别是它使用了select,这样您就不会永远在s.accept上阻塞。我们被特别告知要编写两个脚本,一个使用线程模块,另一个使用select。@ThomasVanhelden我编辑了我的答案,这样做不使用select。这就是我需要的!谢谢!