一:http请求本质阻塞
import socket
import select
client=socket.socket()
client.connect(('www.baidu.com',80))#IO阻塞
print("链接成功")
client.send(b'GET / HTTP/1.0\r\nHost:www.baidu.com\r\n\r\n')
data=client.recv(1024)#IO阻塞
print(data)
二:http请求本质阻塞
client=socket.socket()
client.setblocking(false)
client.connect(('www.baidu.com',80))#IO阻塞
print("链接成功")
client.send(b'GET / HTTP/1.0\r\nHost:www.baidu.com\r\n\r\n')
data=client.recv(1024)#IO阻塞
print(data)
回调函数:
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。(by常溪玲)
三:异步IO请求
def f1(data):
print('保存到数据库',data)
def f2(data):
print('保存到文件',data)
class HttpRequest(object):
def __init__(self,sk,host,callback):
self.socket=sk
self.host=host
self.callback=callback
def fileno(self):#自定fileno()方法
return self.socket.fileno()#返回socket的文件描述符
class AsyncRequest(object):
def __init__(self):
self.conn=[]
self.connection=[]
def addrequest(self,host,callback):
try:
sk=socket.socket()
sk.setblocking(False)
sk.connect((host,80))
except Exception as e:
pass
finally:
sk=HttpRequest(sk,host,callback)#封装socket,本质还是调用socket的fileno函数,添加回调函数
self.conn.append(sk)
self.connection.append(sk)
def run(self):
while True:
#rlist表示有人发送数据
#wlist表示已经和别人链接成功
#elist表示链接有错误
rlist,wlist,elist=select.select(self.conn,self.connection,self.conn,0.05)
#在windows中self.conn为空时,直接报错,但在linux当中仍会执行
for w in wlist:
print('%s链接成功'%w.host)
information='GET / HTTP/1.0\r\nHost:%s\r\n\r\n'%w.host
w.socket.send(bytes(information,encoding='utf-8'))
self.connection.remove(w)
for r in rlist:
data = b''
while True:
try:
chunk=r.socket.recv(2048)
data+=chunk
except Exception as e:
break
r.callback(data)
r.socket.close()
self.conn.remove(r)
if len(self.conn)==0:
break
if __name__=="__main__":
#添加回调函数
urldict=[{'host':'www.baidu.com','function':f1},{'host':'www.baidu.com','function':f2},{'host':'www.163.com','function':f1}]
request=AsyncRequest()
for host in urldict:
request.addrequest(host['host'],host['function'])
request.run()
四:异步io请求
def f1(data):
print('保存到数据库',data)
def f2(data):
print('保存到文件',data)
#处理响应数据
class HttpResponse(object):
def __init__(self,data):
self.data=data
self.headers=dict()
self.body=""
self.dealdata(data)
def dealdata(self,data):
headers,body=self.data.split(b'\r\n\r\n',1)#分割请求头和请求体
self.body=body
headers_list=headers.split(b'\r\n')#将请求头逐个分开
for head in headers_list:
tmp=head.decode('utf-8').split(':',1)#获取每个头的键值对
if len(tmp)==2:
self.headers.setdefault(tmp[0],tmp[1])
#封装socket,添加host属性,实现filno()方法并返回,socket本身的文件对象描述符
class HttpRequest(object):
def __init__(self,sk,host,callback):
self.socket=sk
self.host=host
self.callback=callback
def fileno(self):#自定fileno()方法
return self.socket.fileno()#返回socket的文件描述符
#使用select实现io多路复用,请求相应网址,拿到返回数据
class AsyncRequest(object):
def __init__(self):
self.conn=[]
self.connection=[]
def addrequest(self,host,callback):
try:
sk=socket.socket()
sk.setblocking(False)
sk.connect((host,80))
except Exception as e:
pass
finally:
sk=HttpRequest(sk,host,callback)
self.conn.append(sk)
self.connection.append(sk)
def run(self):
while True:
#rlist表示有人发送数据
#wlist表示已经和别人链接成功
#elist表示链接有错误
rlist,wlist,elist=select.select(self.conn,self.connection,self.conn,0.05)
#在windows中self.conn为空时,直接报错,但在linux当中仍会执行
for w in wlist:
print('%s链接成功'%w.host)
information='GET / HTTP/1.0\r\nHost:%s\r\n\r\n'%w.host
w.socket.send(bytes(information,encoding='utf-8'))
self.connection.remove(w)
for r in rlist:
data = b''
while True:
try:
chunk=r.socket.recv(2048)
data+=chunk
except Exception as e:
break
tk=HttpResponse(data)
# r.callback(data)
r.socket.close()
self.conn.remove(r)
if len(self.conn)==0:
break
if __name__=="__main__":
urldict=[{'host':'www.baidu.com','function':f1},{'host':'www.163.com','function':f1}]
request=AsyncRequest()
for host in urldict:
request.addrequest(host['host'],host['function'])
request.run()