2017-10-18 12 views
2

je code suivant, serveur accepter la connexion réseau, le transmettre à l'enfant à traiter avec Manager().Queue():processus serveur a commencé par multiprocessing.Manager() rend la prise fermée immédiatement canalisée pas

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 ne fonctionne pas attendu, je pense que c'est parce que le processus de serveur de Manager ont une référence sur ce socket, lsof -i confirmé. Comment faire face à cela? J'ai trouvé il n'y a pas un moyen de fermer la socket dans Manager processus, shutdown pourrait faire l'affaire mais pas ce que je veux.

+0

Ce que je peux voir, c'est que Server.run ferme le socket juste après l'avoir placé dans une file d'attente. Donc, cette socket est la file d'attente est fermée à partir de là. – ForceBru

+0

@ForceBru non, l'enfant pourrait l'utiliser normalement. –

+0

Quelle est votre question? Pourquoi y a-t-il un autre processus? Ou pourquoi la prise ne se ferme pas? Et que voulez-vous dire par "ne ferme pas"? – bnaecker

Répondre

1

Problème intéressant. Je ne sais pas si c'est utile, mais j'ai trouvé votre code un peu bizarre au début, car envoyer des objets socket en utilisant Manager().Queue() à un autre processus ne semble pas être supporté. C'est peut-être le cas, mais l'envoi d'un descripteur de fichier à un autre processus nécessite quelques cerceaux. J'ai un peu changé votre code pour le faire comme je le ferais - essentiellement en réduisant et en reconstruisant les poignées.

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) 

Cela ne laisse pas de prises de courant derrière dans CLOSE_WAIT au moins quand je l'ai couru, et il fonctionne comme je l'attendre à travailler.

+0

merci pour votre réponse. envoyer un objet socket via Queue() est supporté dans python3 (depuis 3.3?). –

+0

J'ai réussi à faire fonctionner votre code sur Ubuntu 16.04 en remplaçant le 'c.close()' dans 'handle_request()' par 'c.shutdown (socket.SHUT_RDWR)'. Aucune prise CLOSE_WAIT laissée en arrière ou quoi que ce soit d'inhabituel. – Hannu

+0

merci, j'ai connu l'arrêt est une option. –