利用epoll 实现HTTP服务器的长链接与非堵塞

epoll

epoll是什么?按照man手册的说法:是为处理大批量句柄而作了改进的poll。当然,这不是2.6内核才有的,它是在2.5.44内核中被引进的(epoll(4) is a new API introduced in Linux kernel 2.5.44),它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。

epoll原理:

  • 内存映射(mmap): (共享内存,类似于公有变量 )新建一块不属于应用程序内存及操作系统内存,但两者都能调用的内存,将要操作的进程放进去
  • 事件就绪通知: 进程调动时(收到消息时)响应 ,epoll事先于公共内存里注册一个文件描述符,**文件描述符(fd)**就绪时就会激活进程,即收到数据时激活进程

区别于普通单进程单线程:

  • 普通单进程单线程HTTP服务器为轮询 select/poll(有/无数量限制的轮询)
  • 普通单进程单线程HTTP服务器是将应用程序内存内资源(进程)复制进操作系统内存,处理后删除

epell实现非阻塞长链接HTTP服务器:

# 创建一个epoll对象
epl = select.epoll()

# 将监听套接字对应的fd注册到epoll中
epl.register(tcp_server_socket.fileno(), select.EPOLLIN)

fd_event_dict = dict()

while True:

    fd_event_list = epl.poll()  # 默认会堵塞,直到 os监测到数据到来 通过事件通知方式 告诉这个程序,此时才会解堵塞

    # [(fd, event), (套接字对应的文件描述符, 这个文件描述符到底是什么事件 例如 可以调用recv接收等)]
    for fd, event in fd_event_list:
        # 等待新客户端的链接
        if fd == tcp_server_socket.fileno():
            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:
                service_client(fd_event_dict[fd], recv_data)
            else:
                fd_event_dict[fd].close()
                epl.unregister(fd)
                del fd_event_dict[fd]

猜你喜欢

转载自blog.csdn.net/weixin_44850984/article/details/89600652