2017-10-18 93 views
2

我有以下的代碼,服務器接受的網絡連接,它傳遞給孩子Manager().Queue()處理:服務器進程使得管道插座不立即關閉

q = Manager().Queue() 

class Server: 

    def run(self, host, port): 
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     s.bind((host, port)) 
     s.listen(1) 

     print('parent', os.getpid()) 

     while True: 
      c, _ = s.accept() 
      q.put(c) 
      c.close() 

def handle_request(): 
    print('child', os.getpid()) 
    while True: 
     c = q.get() 
     time.sleep(1) 
     print(c.recv(4)) 
     c.close() 

Process(target=handle_request, args=()).start() 
Server().run('127.0.0.1', 10000) 

close不作爲工作預計,我認爲這是因爲Manager的服務器進程窗口對該套接字有參考,​​lsof -i已確認。如何處理這個?我發現沒有辦法在Manager進程中關閉套接字,shutdown可以做到這一點,但不是我想要的。

+0

我能看到的是'Server.run'將它放入隊列後立即關閉套接字。所以那個套接字是從那以後關閉的隊列。 – ForceBru

+0

@ForceBru不會,孩子可以正常使用它。 –

+0

你的問題是什麼?爲什麼還有另一個過程?或者爲什麼套接字不關閉? 「不關閉」是什麼意思? – bnaecker

回答

1

有趣的問題。

我不確定這是否有幫助,但我發現你的代碼在開始時有點奇怪,因爲使用Manager().Queue()向另一個進程發送套接字對象聽起來並不像它受支持。它可能是,但發送一個文件描述符到另一個進程需要幾圈。我改變你的代碼做一點,因爲我會這樣做 - 基本上減少和重建手柄。

from multiprocessing import Manager, Process 
from multiprocessing.reduction import reduce_handle, rebuild_handle 
import socket 
import os 
from time import sleep 

q = Manager().Queue() 


class Server: 
    def run(self, host, port): 
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
     s.bind((host, port)) 
     s.listen(1) 

     print('parent', os.getpid()) 

     while True: 
      c, _ = s.accept() 
      foo = reduce_handle(c.fileno()) 
      q.put(foo) 
      c.close() 


def handle_request(): 
    print('child', os.getpid()) 
    while True: 
     bar = q.get() 
     sleep(1) 
     barbar = rebuild_handle(bar) 
     c = socket.fromfd(barbar, socket.AF_INET, socket.SOCK_STREAM) 
     print(c.recv(4)) 
     c.shutdown(socket.SHUT_RDWR) 

Process(target=handle_request, args=()).start() 
Server().run('127.0.0.1', 10000) 

這不留下任何插座在CLOSE_WAIT至少,當我跑它,和它的作品,我會期望它的工作。

+0

感謝您的回答。 python3支持通過Queue()發送套接字對象(從3.3開始)。 –

+0

我使用'c.shutdown(socket.SHUT_RDWR)'替換了'handle_request()'中的'c.close()',從而讓你的代碼在Ubuntu 16.04上運行得非常好。沒有CLOSE_WAIT套接字或其他任何異常。 – Hannu

+0

謝謝,我知道關機是一種選擇。 –