自定义异步IO

一: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()

 

posted @ 2019-08-09 15:44  JuiceWoo  阅读(183)  评论(0编辑  收藏  举报