linux 多进程 缺点

fork有一些副作用,其中最明显的就是重复的文件描述符。比如,socket, 磁盘上的文件,终端(标准输入、输出,错误)或某些其他文件类对象。

因为一个进程的fork是一个准确的拷贝,它继承了父进程的所有文件描述符和socket,所以就可能遇到这样一个情况,那就是父进程和子进程对于一个单一的远程主机,都有一个开放的连接.

这并不好,有几个原因,如果两个进程都视图通过socket通信,结果就可能混淆。另外一点是,两个进程都要调用 close() ,连接才能真正被关闭。因此,一些协议中,使用关闭socket作为某些操作结束信号的情况会出现问题。除非父进程和子进程都关闭了。

这个问题的解决办法是在fork之后,只要进程不用 socket的时候就马上关闭它。

#!/usr/bin/env python

#!coding=utf-8

"""

forking 服务器

多进程服务器

"""

import socket ,traceback, os,sys

import time

def reap():

    print "in reap"

    """

    处理子进程

    """

    while 1:

        try:

            print "in reap ,pid=%s"%(getpid())

            result = os.waitpid(-1 , os.WNOHANG)  # -1 表示等待所有的子进程结束,作用相当于调用wait ,WNOHANG表示不使父进程挂起,而立即返回

            print "000000000000000"

            if not result[0]:

                break

        except:

            break

        print "reaped child process %d" % result[0]

def getpid():

    return os.getpid()

host=''

port=9002

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 at %d listening for connection" % getpid()

if __name__ == "__main__":

    while 1:

        try:

            print "accept , pid= %s"%(getpid())

            clientsock , clientaddr = s.accept()

            print "start accpet"

        except KeyboardInterrupt:

            raise

        except:

            traceback.print_exc()

            continue

        #reap()

        pid = os.fork()

        print "*****************"

        if pid:

            #子父进程中

            #this is the parent process .close the child's socket

            print "in parent socket"+str(clientsock)

            print "in parent port=%s"%str(port)

            print "in parent s=%s"%str(s)

            """

            这里为什么要关闭clientsock呢,这里解释(this is the parent process .close the child's socket)

            关闭的是子线程的socket,我觉得是写错了,

            应该关闭的是父进程的client的socket连接,因为这里是在父进程里面,这里为什么要关闭呢,

            因为多进程是, 子进程会复制父进程的数据,那么这样clientsocket,就会存在2次饮用(父进程一个,

            子进程一个) ,如果每创建一次子进程都增加一次引用的话,这样就会消耗系统的资源,所以这里应该关闭

            """

            clientsock.close()

            #s.close()

            print "in parent socket"+str(clientsock)

            continue

        else:

            #在子进程中

            #from here on . this is child

            #clientsock.close()

            print "in child socket"+str(clientsock)

            print "in child port=%s"%str(port)

            print "in child s=%s"%str(s)

            """

            子进程里面也有s, 父进程也有s,如果这时候,客户端有连接的话,就有可能出现混乱的情况,所以这里选择关闭

            子进程的s

            """

            s.close()

        #process the connection

        try:

            print "child from %s being handled bu pid %d"%\

            (clientsock.getpeername(), os.getpid())

        #不停的循环接收数据

            while 1:

                data = clientsock.recv(4096)

                print str(data) + " , pid = %s"%(getpid())

                if not len(data):

                    break

                clientsock.sendall(data)

        except(KeyboardInterrupt, SystemExit):

            raise

        except:

            traceback.print_exc()

    #close the connection

        try:

            print "断开连接 ,pid=%s"%(getpid())

            clientsock.close()

        except KeyboardInterrupt:

            raise

        except:

            traceback.print_exc()

        print "进程结束,pid=%s"%(getpid())

        sys.exit(0)