Несколько процессов, совместно использующих сокет прослушивания: когда входит новый процесс, почему останавливается старый? - PullRequest
2 голосов
/ 17 августа 2011

Этот код является серверной частью моей прокси-программы, и его функция заключается в создании процесса сокета и разветвления четыре для принятия одного за другим.

В моей программе я использую модель gevent для отправки всех своих функций, и перед тем, как изменить ее на несколько процессов, с моей программой все в порядке.но теперь, когда я использую второй процесс, первый останавливается, я не нахожу, где что-то не так, может быть, функция 'accept' или мое событие - остановка отправки.

Это уже беспокоило меня в течение двух дней, я надеюсь, что кто-то может мне помочь.

Кстати, мой английский плохой, я изо всех сил стараюсь объяснить это, надеясь, что вы понимаете.

 class Client(object):
    def __init__(self, ent, ev):
        ...  

    def receive( self ):
        ...
        if "Content-Length" in dic:
            self.ent_s_send = core.event(core.EV_WRITE,
                                         self.conn.fileno(),
                                         self.ser_send,
                                         [self.conn,self.body]
                                         )
            self.recv_ent = core.event(core.EV_READ, 
                                       self.sock.fileno(),
                                       self.recv_content
                                      )
            self.recv_ent.add()
        ...

    def recv_content(self, ent, ev):
        ...
        self.n = self.sock.recv_into(self.msg,
                                     min(self.total-self.num, 20000),
                                     socket.MSG_DONTWAIT)

        **time.sleep(0.1)**  
        #if i add it here to let the event slow down the problem solved, how it could be? 

        self.num += self.n
        self.msg_buffer.fromstring(self.msg.tostring()[:self.n])
        ...
        if self.total > self.num:  #if not the last msg continue recving and sending...
            self.ent_s_send.add()
            self.recv_ent.add()
        ...

    def ser_send(self, ent, ev):
        ...
        num = self.conn.send(self.msg_buffer,socket.MSG_DONTWAIT)
        ...
        self.msg_buffer = self.msg_buffer[num:]

 ...
 ...

 class Server(object):
    def __init__( self ):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind(('localhost', 18001))
        self.sock.listen(50)
        self.mutex = multiprocessing.Lock()

    def loop( self, ):

        for i in range(0,4):
            pid = os.fork()
            if pid == 0 or pid == -1:
                break

        if pid == -1:
            print "Fork failed!!!"
            sys.exit()

        elif pid == 0:   **# create four child ps to accept the socket!**
            print "Child  PID =  %d" % os.getpid()
            core.init()
            self.event = core.event(core.EV_READ,
                                self.sock.fileno(),
                                self.onlink)
            self.event.add()
            core.dispatch()

        else:
            os.wait()

    def onlink( self, ent, ev):
        self.mutex.acquire()
        print 'Accept PID = %s' % os.getpid()
        try:
            self.conn, self.addr = self.sock.accept()   
            **#I think 'accept' is the the problem, but I cannot see how.** 

        except socket.error, why:
            if why.args[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED]:
                return
            else:
                raise
        print self.sock,self.conn,self.addr
        self.mutex.release()
        print 'Release PID = %s' % os.getpid()
        cc = Chat( self.conn, self.sock )
        self.event.add()



if __name__ == '__main__':

    s1 = Server()
    s1.loop()

1 Ответ

1 голос
/ 17 августа 2011

accept() является blocking call. Клиент будет ждать бесконечно долго. Удержание мьютекса над блокирующей операцией, подобной этой, является Bad Idea TM , поскольку вы полностью блокируете все другие параллельные процессы.

Кроме того, как заметил @Maxim в комментариях, вам не нужно блокироваться вокруг accept(). Просто позвольте ОС разрешить отмену входящих соединений и передать их вашим процессам.

...