import socket
import select
class MakeRequest:
    '''用来将socket和url信息以及回调函数进行封装'''
    def __init__(self, sock, host, callback):
        self.sock = sock
        self.host = host
        self.callback = callback
    def fileno(self):
        return self.sock.fileno()  # 可以放到select中
class AsyncRequest:
    '''根据发来的host进行访问'''
    def __init__(self):  # 用来盛放socket对象
        self.wlist = []  # 监听w
        self.rlist = []  # 监听r
    def add_socket(self, host, callback):
        '''根据host生成socket'''
        try:
            sock = socket.socket()
            sock.setblocking(0)  # 设置为非阻塞
            sock.connect((host, 80))  # 对主机进行连接,默认为80端口
        except BlockingIOError as e:
            pass
        request = MakeRequest(sock, host, callback)  # 将sock以及对应的封装在一起
        self.wlist.append(request)
        self.rlist.append(request)
        # 检测是否连接上了
    def run(self):
        '''运行socket'''
        while 1:
            r, w, e = select.select(self.rlist, self.wlist,self.rlist, 0.05)
            for w in self.wlist:
                '''对socket对象进行监听,如果w有动静,则说明连接上了'''
                print(w.host, '已经连接上')
                info = "GET / HTTP/1.0\r\nHost:%s\r\n\r\n" % (w.host)
                w.sock.send(bytes(info, encoding='utf-8'), )
                self.wlist.remove(w)
            for r in self.rlist:  # 用来接收数据
                recv = bytes()
                while 1:
                    try:
                        chunk = r.sock.recv(8096)
                        recv += chunk
                    except Exception as e:
                        break
                print(recv)
                r.callback(recv)
                r.sock.close()
                self.rlist.remove(r)
            if len(self.rlist) == 0:  # 所有的socket都处理完成
                break
# 准备接口
def f1(data):
    print('f1')
def f2(data):
    print('f2')
def f3(data):
    print('f3')
'''不同的url可以有不同回调函数'''
url_list = [
    {'host': 'www.baidu.com', 'callback': f1},
    {'host': 'www.google.com', 'callback': f2},
    {'host': 'www.cnblogs.com', 'callback': f3},
]
# 处理回调函数的时候,可以进行再次封装,将url和socket封装在一块
req = AsyncRequest()
for url in url_list:
    # 先对urllist进行格式改变
    req.add_socket(url['host'], url['callback'])
req.run()