gpt4 book ai didi

python - Python线程将无法开始使用套接字

转载 作者:行者123 更新时间:2023-11-28 22:34:19 27 4
gpt4 key购买 nike

我对使用套接字和线程的程序有问题。

我已经做了一个套接字服务器,它在一个线程中添加了客户端,但是客户端线程永远不会启动...

这是我的代码:

套接字服务器

import socket, threading, logging, sys
from client_thread import ClientThread

class SocketServer:
CLIENTS = list()

def __init__(self, server_ip, server_port, max_connections):
try:
self.tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.tcpsock.bind((server_ip, server_port))
self.tcpsock.listen(10)

logging.info('Socket server successfully started !')
except Exception as e:
logging.error(format(e))

def start(self):
from src.realmserver.core.hetwan import EmulatorState, Core

while (Core.STATE == EmulatorState.IN_RUNNING):
try:
(clientsock, (ip, port)) = self.tcpsock.accept()
new_client = threading.Thread(target=ClientThread, args=[len(self.CLIENTS), ip, port, clientsock])
self.CLIENTS.append(new_client)
new_client.start()
except Exception as e:
print format(e)

for client in self.CLIENTS:
client.join()

和客户端线程
import logging, string, random

class ClientThread:
def __init__(self, client_id, client_ip, client_port, socket):
self.client_id = client_id
self.client_ip = client_ip
self.client_port = client_port
self.socket = socket
logging.debug('(%d) Client join us !', client_id)

def run(self):
key = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(32))

print self.send('HC%s' % key)

while True:
entry = self.socket.recv(4096)
entry.replace("\n", "")

if not entry:
break
else:
logging.debug('(%d) Packet received : %s', self.client_id, str(entry))

self.kill()

def send(self, packet):
return self.socket.send("%s\x00" % packet)

def kill(self):
self.socket.close()
logging.debug('(%d) Client is gone...', self.client_id)

很抱歉缩进不好,它是表格,而不是我的文件。

请帮我 :(

在此先谢谢您(抱歉英语不好,我是法语...。)

最佳答案

您的Server实例start函数中具有以下代码行:

new_client = threading.Thread(target=ClientThread,
args=[len(self.CLIENTS), ip, port, clientsock])
target=threading.Thread参数必须是可调用的函数。这里 ClientThread是类 ClientThread的构造函数的名称,因此它是可调用的函数,返回该类的实例。请注意,它实际上尚未被调用! args=参数通常是一个元组,但实际上可以使用列表。当您使用此特定线程模型时,这些参数将在最终被调用后传递给 target函数。 (您还可以使用 kwargs=和字典来传递关键字参数。)

现在发生的事情有些棘手。既然已经评估了两个参数( target=args=),Python运行时将创建一个 threading.Thread类的新实例。目前,这个新实例只是一个数据对象。

如果我们添加 print语句/函数(尚不清楚这是py2k还是py3k代码),我们可以看到对象本身:
print('new_client id is', id(new_client))

这将打印如下内容:1
new_client id is 34367605072

接下来,将其添加到列表中,然后调用其 start:
self.CLIENTS.append(new_client)
new_client.start()

列表添加非常简单,但是 start非常棘手。
start调用本身实际上创建了一个新的OS/运行时线程(其ID与数据对象的ID不相关-原始线程ID是内部实现细节)。这个新线程以其 run方法开始运行。2默认的 run方法实际上是:3
try:
if self.__target:
self.__target(*self.__args, **self.__kwargs)
finally:
# Avoid a refcycle if the thread is running a function with
# an argument that has a member that points to the thread.
del self.__target, self.__args, self.__kwargs

由于您使用的是常规 threading.Thread实例对象,因此您将获得此默认行为,其中 new_thread.start()会创建新线程本身,然后调用默认的 run方法,该方法会调用默认的 self.__target方法,即 ClientThread类-实例-创建功能。

因此,现在,在新线程中,Python创建了 ClientThread对象的实例,并使用保存在 __init__实例中的 self.__argsself.__kwargs调用其 new_thread(该实例本身在原始Python和新线程之间共享)。

这个新的 ClientThread对象执行其 __init__代码并返回。这等效于读取 run方法:
def run(self):
ClientThread(**saved_args)

请注意,这不是:
def run(self):
tmp = ClientThread(**saved_args)
tmp.run()

也就是说,永远不会调用 run实例的 ClientThread方法。仅调用 run实例的 threading.Thread方法。如果您修改 ClientThread__init__方法以打印其ID,您将看到此ID与 threading.Thread实例的ID不同:
class ClientThread:
def __init__(self, client_id, client_ip, client_port, socket):
print('creating', id(self), 'instance')

它将打印一个不同的ID(并且肯定在 new_client id is行之后打印):
new_client id is 34367605072
creating 34367777464 instance

如果将其他 print添加到 run方法中,您将看到它永远不会被调用。

该怎么办

您在这里有两个主要选择。
  • 您可以将ClientThread设置为threading.Thread的子类:
    class ClientThread(threading.Thread):
    def __init__(self, client_id, client_ip, client_port, socket):
    ...
    threading.Thread.__init__(self)

    在这种情况下,您可以自己创建客户端对象,而不是使用threading.Thread来创建它:
    new_thread = ClientThread(...)
    ...
    new_thread.start()
    .start方法将是threading.Thread.start,因为您尚未覆盖它,然后该方法将创建实际的OS/运行时线程,然后调用run方法,因为您确实覆盖了它,所以它将成为run
  • 或者,您可以创建一个标准的threading.Thread对象,为它提供target,然后让此target调用您对象的run方法,例如:
    new_client = ClientThread(...)
    new_thread = threading.Thread(target=new_client.run, ...)
    ...
    new_thread.start()

    选择是您自己的:子类化,或使用单独的对象。


  • 1实际的ID高度依赖于实现。

    2到达该 run函数的路径有些复杂,它会经过引导代码进行内部初始化,然后为您调用 self.run,而不会传递任何参数。仅向您保证会以某种方式输入 self.run;您不应该依赖“如何”。

    3至少,这是Python 2.7和3.4中的代码;其他实现可能会略有不同。

    关于python - Python线程将无法开始使用套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39069704/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com