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)