epoll并发

epoll仅限Linux或Unix系统(服务器)。

片面讲epoll并发原理:1.数据共享(内存映射(mmap)技术),即client_socket_list和操作系统共享,省去拷贝fb给操作系统的时间

                     2.事件监听(基于事件的就绪通知方式),不再是一直遍历客户端套接字列表来得知哪个套接字有数据,而是哪个套接字有数据直接传给操作系统。

epoll实现http服务器:

  1 import socket
  2 import re
  3 import select
  4 
  5 
  6 def service_client(client_socket, requests):
  7     """为这个客户端返回数据"""
  8     # 1.接收浏览器发送过来的请求
  9     # request = client_socket.recv(1024).decode('utf-8')
 10     # 将浏览器请求的头部信息,根据换行拆分成一个列表
 11     headers = requests.splitlines()
 12     # print(headers[0])   # GET /XXX/XXXX HTTP/1.1
 13     ret = re.match(r'[^/]+(/[^ ]*)', headers[0])
 14     # print(ret.group())
 15     file_name = ''
 16     if ret:
 17         # 符合正则的值为GET /XXX/XXX和/XXX/XXX 取后面这个group(1)
 18         file_name = ret.group(1)
 19         # 如果浏览器请求的是127.0.0.1(也就是只有一个/),那么让浏览器显示主页(index.html)
 20         if file_name == '/':
 21             file_name = '/index.html'
 22 
 23     # 2.返回http格式的数据给浏览器
 24     try:
 25         f = open('jQuery响应式网站导航菜单'+file_name, 'rb')
 26     except:
 27         # 如果浏览器访问的页面不存在,则返回404
 28         response = "HTTP/1.1 404 \r\n"
 29         response += 'Content-Type: text/html;charset=utf-8\r\n'
 30         response += '\r\n'
 31         response += "您所访问的地址或文件不存在"
 32         # 发送网页的headers
 33         client_socket.send(response.encode('utf-8'))
 34     else:
 35         # 2.1 准备发送给浏览器的header
 36         html_content = f.read()
 37         f.close()
 38         response = "HTTP/1.1 200 OK\r\n"
 39         response += 'Content-Type: text/html;charset=utf-8\r\n'
 40         response += 'Content-Length: %d\r\n' % len(html_content)
 41         response += '\r\n'
 42         # 发送网页的headers
 43         client_socket.send(response.encode('utf-8'))
 44 
 45         # 发送网页的body
 46         client_socket.send(html_content)
 47 
 48     # 关闭套接字
 49     # client_socket.close()
 50 
 51 
 52 def main():
 53     """用来完成整体的控制"""
 54     # 1.创建套接字
 55     tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 56     tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 57 
 58     # 2.绑定
 59     tcp_server_socket.bind(('', 7788))
 60 
 61     # 3.设置为被动监听
 62     tcp_server_socket.listen(128)
 63     tcp_server_socket.setblocking(False)  # 将套接字变为非堵塞
 64 
 65     # 创建一个epoll对象
 66     epl = select.epoll()
 67 
 68     # 将监听套接字对应的fd注册到epoll中
 69     epl.register(tcp_server_socket.fileno(), select.EPOLLIN)
 70 
 71     fd_evevt_dict = dict()
 72     while True:
 73         # 默认会堵塞,直到os检测到数据到来,通过事件通知方式告诉这个程序,此时才会借堵塞
 74         # [(fd,event), (fd, event)...]
 75         # fd:套接字对应的文件描述符,evevt:这个文件描述符到底是什么事件
 76         fd_evevt_list = epl.poll()
 77         for fd, event in fd_evevt_list:
 78             if fd == tcp_server_socket.fileno():
 79                 # 4.等待客户端连接
 80                 new_socket, client_adress = tcp_server_socket.accept()
 81                 epl.register(new_socket.fileno(), select.EPOLLIN)
 82                 fd_evevt_dict[new_socket.fileno()] = new_socket
 83             # 除了监听套接字,剩下的都是客户端套接字
 84             elif event == select.EPOLLIN:
 85                 # 判断已经链接的客户是否有数据发送过来
 86                 client_socket = fd_evevt_dict[fd]
 87                 recv_data = client_socket.recv(1024).decode('utf-8')
 88                 if recv_data:
 89                     service_client(client_socket, recv_data)
 90                 else:
 91                     client_socket.close()
 92                     epl.unregister(fd)
 93                     del fd_evevt_dict[fd]
 94 
 95     # 关闭监听套接字
 96     tcp_server_socket.close()
 97 
 98 
 99 if __name__ == '__main__':
100     main()

具体epoll详解参照:https://blog.csdn.net/xiajun07061225/article/details/9250579

猜你喜欢

转载自www.cnblogs.com/zuzhuangmengxiang/p/12696934.html