在Python线程模块中停止服务器程序

0 投票
1 回答
3428 浏览
提问于 2025-04-27 12:14

我正在用Python写一个简单的信息服务器,这个服务器能对三种不同的命令做出回应。我需要使用线程模块来处理多个客户端,所以其他处理多个客户端的方法都不适用。每当有客户端向服务器发送'EXIT'命令时,服务器程序应该停止运行。我原以为可以通过在处理客户端的线程中关闭连接和套接字来实现这一点。但是,当我这样做时,服务器在收到'EXIT'后仍然继续运行,并且在下一个客户端尝试连接时崩溃,出现了以下错误:

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()
暂无标签

1 个回答

0

这有点像小技巧,不过你可以在调用 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()

撰写回答