[英]Python thread won't start using socket
我對使用套接字和線程的程序有問題。
我已經做了一個套接字服務器,它在一個線程中添加了客戶端,但是客戶端線程永遠不會啟動...
這是我的代碼:
套接字服務器
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])
threading.Thread
的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
方法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
對象的實例,並使用保存在new_thread
實例中的self.__args
和self.__kwargs
調用它的__init__
(該實例本身在原始Python和新線程之間共享)。
這個新的ClientThread
對象執行其__init__
代碼並返回。 這等效於讀取run
方法:
def run(self):
ClientThread(**saved_args)
請注意,這不是 :
def run(self):
tmp = ClientThread(**saved_args)
tmp.run()
也就是說, 永遠不會調用 ClientThread
實例的run
方法。 僅調用threading.Thread
實例的run
方法。 如果修改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
line 之后打印):
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中的代碼; 其他實現可能會略有不同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.