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()
网友评论