2019-07-08

2019-07-08  本文已影响0人  CC__XX

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()
上一篇 下一篇

猜你喜欢

热点阅读