一,epoll的实现原理就是基于这三个函数来实现的,具体步骤如下:
首先,需要调用epoll_create来创建一个epoll的文件描述符,内核会同时创建一个eventpoll的数据结构。这个数据结构里面会包含两个东西,一个是红黑树,专门用于存储epoll_ctl注册进来的fd文件描述符;另外一个是就绪链表,用来存储epoll_wait调用相关的,已经就绪的那些fd文件描述符。
struct eventpoll{
struct rb_root rbr; // 红黑树的根节点,存储着所有添加到epoll中的需要监控的事件
struct list_head rdlist;// 双链表中存放着将要通过epoll_wait返回给用户的满足条件的事件
};
使用epoll实现http
import socket
import re
import select
def server_client(new_socket,request):
'''为这个客户端返回数据'''
# 1、接收浏览器发过来的请求,即Http请求
# GET / HTTP/1.1
# .....
request_lines = request.splitlines()
print('')
print('>'*20)
print(request_lines)
ret = re.match(r'[^/]+(/[^ ]*)',request_lines[0])
file_name =''
if ret:
file_name = ret.group(1)
print('*'*50,file_name)
if file_name =='/':
file_name ='/index.html'
# 2、返回HTTP格式的数据给浏览器
# 2.1 准备发送给浏览器的Header
# response = 'HTTP/1.1 200 OK\r\n'
# response += '\r\n'
#2.2 准备发给浏览器的Body
# response += '
hahaha
'try:
f =open('../obj'+ file_name,'rb')
except:
response ='HTTP/1.1 404 NOT FOUND\r\n'
response +='\r\n'
response +='---FILE NOT FOUNF---'
new_socket.send(response.encode('utf-8'))
else:
html_content = f.read()
f.close()
request_body = html_content
response_header ='HTTP/1.1 200 OK\r\n'
response_header +='Content-Length: %d\r\n'%len(request_body)
response_header +='\r\n'
response = response_header.encode('utf-8') + request_body
new_socket.send(response)
# 关闭客户端套接字
def main():
'''用来完成整体的控制'''
# 1.创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
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(False)
epl = select.epoll()
epl.register(tcp_server_socket.fileno(),select.EPOLLIN)
fd_event_dict =dict()
while True:
fd_event_list = epl.poll()# 默认会阻塞,知道os检测到数据到来,通过事件通知的方式告诉程序,这时候才会解阻塞
for fd, eventin fd_event_list:
# 4.等待新客户端的链接
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:
# 5、为客户端服务
server_client(fd_event_dict[fd],recv_data)
else:
fd_event_dict[fd].close()
epl.unregister(fd)
del fd_event_dict[fd]
# 6、关闭监听套接字
tcp_server_socket.close()
if __name__ =='__main__':
main()