web服务器--并发web服务器实现-epoll

在linux的网络编程中,很长的时间都在使用select来做事件触发。在linux新的内核中,有了一种替换它的机制,就是epoll。

epoll 是当今 linux 系统采用的方式,一般服务器都是用 epoll 来实现的。epoll 是一种方案,这种方案不使用多进程多线程多协程,而是使用单进程单线程来实现高并发。那我们之前写的单进程单线程非阻塞的程序和epoll有什么区别呢?

我们之前写的程序是建一个列表存储套接字,然后遍历,这种方式叫轮询。明显比较慢。
epoll :是谁收到谁举手,这种方式叫事件通知。

在这里插入图片描述
蓝色表示共享内存,绿色表示存储列表,黄色套接字,白色监听套接字。
程序来实现:

import socket
import re
import select

def service_client(new_client_sock,requst):
    '''为这个客户服务'''

    # 转为列表
    requst_lines = requst.splitlines()

    # 寻找文件名  GET /index.html HTTP/1.1
    # 开头有:GET POST PUT DEL 不一定是GET 所以应该不能用GET匹配。
    file_name = ''
    ret = re.match(r'[^/]+(/[^ ]*)',requst_lines[0])
    if ret:
        file_name = ret.group(1)
        if file_name == '/ ':
            file_name = '/index.html'

    # 2.3 准备body,且这里准备的body不能和之前的字符串一样,直接相加,而是要单独发送。
    # 找到相对应的.html文件
    try:
        f = open('./html'+file_name,'rb')
    except:
        response = 'HTTP/1.1 404 NOT FOUND\r\n'
        response += '\r\n'
        response += '---file not found--'
    else:
        html_content = f.read()
        f.close()

        # 2.返回数据给浏览器,http 格式
        response_body = html_content

        response_header = 'HTTP/1.1 200 OK\r\n'
        response_header += 'Content-Length:%d\r\n' % len(response_body)
        response_header += '\r\n'

        response = response_header.encode('utf-8') + response_body

        # 2.4 发送数据给浏览器
        new_client_sock.send((response))

    # 3.长连接不能使用close关闭套接字,那么我们怎么知道数据已经发完了呢?
    # 在 header 中加入发送数据的长度 Content-Length:
    # new_client_sock.close()


def main():
    '''用来完成整体的控制'''

    # 1.创建套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 2.绑定
    tcp_socket.bind(('', 7890))

    # 3.变为监听套接字
    tcp_socket.listen(128)
    tcp_socket.setblocking(False)  # 将套接字变为非堵塞

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

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

    while True:

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

        # [(fd, event),(套接字对应的文字描述符,这个文件描述符到底是什么事件,例如:可以调用recv接收等)]
        for fd,enent in fd_event_list:

            # 4.等待客户端的链接
            if fd == tcp_socket.fileno():
                new_client_sock, client_addr = tcp_socket.accept()
                epl.register(new_client_sock.fileno(), select.EPOLLIN)
                fd_event_dict[new_client_sock.fileno()] = new_client_sock
            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]

    # 4.关闭监听套接字
    tcp_socket.close()


if __name__ == '__main__':
    main()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值