美文网首页
2019-07-08

2019-07-08

作者: CC__XX | 来源:发表于2019-07-08 23:02 被阅读0次

    epoll基础知识

    多路复用

    1、阻塞 I/O 只能阻塞一个 I/O 操作,而 I/O 复用模型能够阻塞多个 I/O 操作,所以才叫做多路复用
    2、采用epoll模型时创建了一个共享的内存空间,操作系统采用事件通知的方式,使一个进程能同时等待多个文件描述符
    3、这样就可以同时监听多个网络连接 IO, 相对于多进程、多线程切换的开销问题,IO 多路复用可以极大的提升系统效率。

    import socket
    import re
    import select
     
    def service_client(new_socket):
         """为这个客服端返回数据"""
         #1.接收板游览器发送过来的请求.即http请求
         #GET/HTTP/1.1
         #....
         # request = new_socket.recv(1024).decode("utf-8")
         # print(">>>>"*20)
         # print(request)
         request_linest = request.splitlines()
         print("")
         print(">"*20)
         print(request_linest)
         #GET /index.html HTTP/1.1
         #get post put del
         #用正则表达式来匹配index.html
         #在/之前只要不是斜杠 无论一个或者多个都不要
         #取出文件
         ret = re.math(r"[^/]+(/[^ ]*)", request_lines[0])
         file_name = ""
         if ret :
             #匹配成功
             file_name = ret.group(1)
             print("*"*50 ,file_name)
             if file_name == "/":
             file_name =' /index.html '
         #返回http格式的数据给游览器
         #2.1 准备发送给游览器的数据:header
         # f = open("../陈兴的项目","rb")
         try:
             f = open("../陈兴的项目" + file_name, "rb")
         except:
             reponse = "HTTP/1.1 404 NOT FOUND\r\n"
             reponse += "\r\n"
             reponse += "----file not found------"
             now_socket.send(reponse.encode("utf-8"))
    
         else:
             html_content = f.read()
             f.close()
             reponse_body = html_content
             reponse_header = "HTTP/1.1 200 OK\r\n"
             reponse_header = "Content-Length:%d\r\n" % len(reponse_header)
             reponse_header += "\r\n"
             response = reponse_header.encode("utf-8") + reponse_body
             # 2.2  发送给游览器的数据:body
             # reponse = "<h1>hahah</h1>"
             # 将Response Header 发送给游览器
             now_socket.send(reponse.encode("utf-8"))
             # 将Response body 发送给游览器
             request_socket.send(html_content)
         #关闭套接字
         new_socket.close()
    
    def main():
        "作为程序的主控制入口"
        #1.创建套接字
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,这样就保证了,下次运行程序时 可以立即绑定7788端口
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        #2.绑定
        tcp_server_socket.bind(("", 7890))
        #3.变为监听套接字(最大连接数)
        tcp_server_socket.listen(128)
        tcp_server_socket.setblocking(Flase) #设置套接字为非阻塞的
        # 创建一个epool
        epl = select.epoll()
    
        # 将监听的套接字对应的fd 注册到epoll中 括号里的是文件描述符   select.EPOLLIN  是否有输入
        epoll.register(tcp_server_socket.fileno() , select.EPOLLIN)
    
        # {fd:socket}
        fd_event_dict = dict()
    
        # client_socket_list = list()
        while True:
            fd_event_list = epl.poll()
    
            """这个方法默认阻塞,直到检测数据的到来,通过事件通知的方式告诉y
        应用程序,此时才会解阻塞
        列表的样式 [(fd ,event),fd ,event).....]"""
        # 参数fd:套接字对应的文件描述
        # 参数event:这个fd事件什么事件,例如recv接受
            for fd,event  in fd_event_list:
                if fd == tcp_server_socket.fileno():
            # try:
                # 4. 等待新客户端的链接
                    new_socket, client_addr = tcp_server_socket.accept()
                    epl.register(new_socket.fileno(), select.EPOLLIN)
                    fd_event_dict[new_socket.fileno()] = new_socket
                elif event == select.EPOLLIN 
                # 判断已经链接的客服端是否有数据发过来了
                    recv_data = fd_event_dict[fd].recv(1024).decode("utf-8")
                    if recv_data:
                        # 5.为客服端服务
                        service_client(fd_event_dict[fd] ,recv_data)
                    else:
                        # 如果接收到的空数据,应该关闭
                        fd_event_dict[fd].close()
                        epl.unregister(fd)      
                        def fd_event_dict[fd]
                    
            # except Exception as ret:
            #   pass
            # else:
                # new_socket.setblocking(Flase)
                # client_socket_list.append(new_socket)
    
            # for client_socket in client_socket_list:
            #   try:
            #       recv_data =client_socket.recv(1024).decode("utf-8")
            #   except Exception as ret :
            #       pass
            #   else:
            #       if recv_data:
            #           service_client(client_socket ,recv_data)
            #       else:
            #           client_socket.close()
            #           client_socket_list.remove(client_socket)
           
            # 关闭套接字
            tcp_server_socket.close()
    
    
    if __name__ == "__main__":
      main()
    

    相关文章

      网友评论

          本文标题:2019-07-08

          本文链接:https://www.haomeiwen.com/subject/triwhctx.html