封装允许执行命令有超时的类
#!/usr/bin/env python
import os;
import sys;
import time;
import fcntl;
import select;
import signal;
import commands;
import subprocess;
class CRunCmd:
def __init__(self):
pass;
def __AsyncRecv(self, fdSock, nMaxRead = 1024 * 8):
if not fdSock or fdSock.closed:
return (False, '')
#set fd non-block
nFlags = fcntl.fcntl(fdSock, fcntl.F_GETFL);
fcntl.fcntl(fdSock, fcntl.F_SETFL, nFlags | os.O_NONBLOCK)
bRet = False
strRead = ''
try:
#check can be read
if not select.select([fdSock], [], [], 0)[0]:
return (True, '')
strRead = fdSock.read(nMaxRead);
#if read empty, then close it
if len(strRead) <= 0:
fdSock.close();
bRet = True;
except:
bRet = False;
#reset fd
if not fdSock.closed:
fcntl.fcntl(fdSock, fcntl.F_SETFL, nFlags)
return (bRet, strRead)
def Run(self, lsCmd, nTimeOut = 0, nIntervalTime = 1):
oProc = subprocess.Popen(lsCmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
strOut = ''
strErr = '';
nStartTime = time.time()
while True:
print(oProc.poll());
if None != oProc.poll():
break;
#sleep nIntervalTime
time.sleep(nIntervalTime)
bRet, strBuf1 = self.__AsyncRecv(oProc.stdout);
bRet, strBuf2 = self.__AsyncRecv(oProc.stderr);
if len(strBuf1) > 0:
strOut += strBuf1;
if len(strBuf2) > 0:
strErr += strBuf2;
if (nTimeOut > 0) and (time.time() - nStartTime) > nTimeOut:
print("time out...");
break;
#get last buff
bRet, strBuf1 = self.__AsyncRecv(oProc.stdout);
bRet, strBuf2 = self.__AsyncRecv(oProc.stderr);
if len(strBuf1) > 0:
strOut += strBuf1;
if len(strBuf2) > 0:
strErr += strBuf2;
#if not finish, so timeout
if None == oProc.poll():
self.KillAll(oProc.pid)
return (oProc.returncode, strOut, strErr)
def KillAll(self, nKillPid, nKillSignal = signal.SIGKILL):
print("kill pid:%s" %nKillPid)
nRet, strOutput = commands.getstatusoutput('ps -A -o pid,ppid');
if 0 != nRet:
return (False, strOutput);
mapPid = {};
#make all ppid & pid map
for strLine in strOutput.split('\n'):
lsPid = strLine.strip().split();
if 2 != len(lsPid):
continue;
strPid = lsPid[0];
strPPid = lsPid[1];
if strPPid in mapPid.keys():
mapPid[strPPid].append(strPid);
else:
mapPid[strPPid] = [strPid];
#get all kill pid list
lsAllKillPid = [str(nKillPid)];
lsToKillPid = [str(nKillPid)];
while True:
if len(lsToKillPid) <= 0:
break;
lsChild = []
for strPid in lsToKillPid:
if strPid in mapPid.keys():
lsAllKillPid.extend(mapPid[strPid]);
lsChild.extend(mapPid[strPid]);
print("[%s]append:%s" %(strPid, mapPid[strPid]));
lsToKillPid = lsChild;
print("kill pid list\n%s" %lsAllKillPid)
#kill all process
for strPid in reversed(lsAllKillPid):
try:
print("kill %s" %(strPid))
#os.kill(int(strPid), nKillSignal)
except:
pass
return (True, '')
/tmp/a.py
#!/usr/bin/env python
import time;
import os;
import sys;
def Fork():
os.fork();
print("pid:%s" %os.getpid());
if '__main__' == __name__:
for i in xrange(0, int(sys.argv[1])):
print("[%s] befor fork" %os.getpid());
Fork();
print("[%s] after fork" %os.getpid());
time.sleep(1);
print("[%s] start sleep" %os.getpid());
time.sleep(10);
print("[%s] end of process..." %os.getpid());
#test code
if "__main__" == __name__:
oCmd = CRunCmd();
nRet, strOut, strErr = oCmd.Run(['python', '/tmp/a.py', '10'], 5)
print("ret:%s" %nRet);
print("stdout:%s" %strOut);
print("stderr:%s" %strErr);
执行结果:
$python w_p.py
None
None
None
None
None
time out...
kill pid:29443
[29443]append:['29444', '29446', '29450', '29457', '29474']
[29444]append:['29445', '29448', '29454', '29463']
[29446]append:['29449', '29456', '29465']
[29450]append:['29458', '29471']
[29457]append:['29473']
[29445]append:['29447', '29452', '29462']
[29448]append:['29453', '29461']
[29454]append:['29470']
[29449]append:['29455', '29468']
[29456]append:['29467']
[29458]append:['29472']
[29447]append:['29451', '29466']
[29452]append:['29459']
[29453]append:['29460']
[29455]append:['29469']
[29451]append:['29464']
kill pid list
['29443', '29444', '29446', '29450', '29457', '29474', '29445', '29448', '29454', '29463', '29449', '29456', '29465', '29458', '29471', '29473', '29447', '29452', '29462', '29453', '29461', '29470', '29455', '29468', '29467', '29472', '29451', '29466', '29459', '29460', '29469', '29464']
kill 29464
kill 29469
kill 29460
kill 29459
kill 29466
kill 29451
kill 29472
kill 29467
kill 29468
kill 29455
kill 29470
kill 29461
kill 29453
kill 29462
kill 29452
kill 29447
kill 29473
kill 29471
kill 29458
kill 29465
kill 29456
kill 29449
kill 29463
kill 29454
kill 29448
kill 29445
kill 29474
kill 29457
kill 29450
kill 29446
kill 29444
kill 29443
ret:None
stdout:
stderr: