2016-04-02 77 views
1

我有一個TCP服務器和客戶端。在服務器腳本的某個時候,我啓動了一個進程,它需要能夠獲取每個新連接並向其發送數據。爲了做到這一點,我有一個multiprocessing.Queue(),我希望將主進程中的每個新連接放到這個連接上,以便我打開的進程可以從中獲取連接並向其發送數據。但是,看起來你不能將任何你想要的東西傳遞給隊列。當我嘗試通過連接(一個套接字對象)時,我得到:Python的 - 傳遞一個TCP套接字對象的多隊列

Traceback (most recent call last): 
    File "/usr/lib/python2.7/multiprocessing/queues.py", line 266, in _feed 
    send(obj) 
TypeError: expected string or Unicode object, NoneType found 

是否有任何替代方案可以使用?

+0

你不能那樣做。 'Queue'旨在發送Python對象,而套接字涉及特定於OS的數據(例如套接字fd),因此它們不能簡單地傳遞給子進程。 – myaut

+0

好吧,我找到了解決這個問題的方法。然而,即使你說這是不可能的,我真的很想看到實際做到這一點的方式。 –

回答

5

發送通過multiprocessing.Queue插座正常工作的出發與python3.4,因爲從該版本ForkingPickler is used序列化被放置在隊列中的對象和Pickler會知道如何序列插座和一個包含文件句柄的其他對象。

multiprocessing.reduction.ForkingPickler類已經存在於python2.7中,並且可以使用pickle套接字,它只是不被multiprocessing.Queue使用。

如果您不能切換到python3.4 +和確實需要類似的功能在python2.7一種解決方法是創建一個使用ForkingPickler序列化對象的功能,如:

from multiprocessing.reduction import ForkingPickler 
import StringIO 

def forking_dumps(obj): 
    buf = StringIO.StringIO() 
    ForkingPickler(buf).dump(obj) 
    return buf.getvalue() 

相反直接發送套接字然後你需要發送它的醃製版本,並在消費者中取消它。簡單的例子:

from multiprocessing import Queue, Process 
from socket import socket 
import pickle 

def handle(q): 
    sock = pickle.loads(q.get()) 
    print 'rest:', sock.recv(2048) 

if __name__ == '__main__': 
    sock = socket() 
    sock.connect(('httpbin.org', 80)) 
    sock.send(b'GET /get\r\n') 
    # first bytes read in parent 
    print 'first part:', sock.recv(50) 

    q = Queue() 
    proc = Process(target=handle, args=(q,)) 
    proc.start() 
    # use the function from above to serialize socket 
    q.put(forking_dumps(sock)) 
    proc.join() 

使插座與pickle纔有意義,在這裏多的背景下,這是沒有意義的將其寫入到一個文件,並在以後使用或嘗試使用它在不同的PC或原後過程已結束。因此,在全球範圍內製作插座不是一個好主意(例如通過使用copyreg機制)。

+1

這就是我一直在尋找的!這樣,我可以將套接字傳遞給進程,並且工作得很好!謝謝! –