epoll版http服务器

epoll是事件通知方式接收数据,效率比轮询要高

代码:

  1 import socket
  2 import re
  3 import select
  4 
  5 
  6 def client_server(new_client,recv_data):
  7     # 接收客户端请求
  8     # recv_data = new_client.recv(1024).decode("utf-8")
  9     # 把读出的数据分行
 10     recv_data_lines = recv_data.splitlines()
 11     # 正则匹配GET后面的请求的页面
 12     # [^/]表示非“/”字符 +表示至少1个或多个,[^ ]只要不是空格,*表示0个或多个
 13     ret = re.match(r"[^/]+(/[^ ]*)",recv_data_lines[0])
 14 
 15     # ret = re.search(r"/[^ ]*",recv_data_lines[0])  # 查找第一次“/”后面非空格的字符串
 16     file_name = ret.group(1)
 17     # 打开文件
 18     try:
 19         f = open("./html" + file_name,"rb")
 20     except:
 21         # 创建返回数据 HEADER
 22         response = "HTTP/1.1 404 NOT FOUND\r\n"
 23         response += "\r\n"
 24         response += "-----NOT FOUND----"
 25         # 发送数据到客户端
 26         new_client.send(response.encode("utf-8"))
 27     else:
 28         # 读出数据
 29         html_content = f.read()
 30         # 把读出的数据放到BODY体里面
 31         response_body = html_content
 32 
 33         # 创建返回数据 HEADER
 34         response_header = "HTTP/1.1 200 ok\r\n"
 35         # 告诉浏览器发送过去的长度
 36         response_header += "Content-Length:%d\r\n" % len(response_body)
 37         response_header += "\r\n"
 38         # 把HEADER和BODY拼接在一起
 39         response = response_header.encode("utf-8") + response_body
 40         # 发送数据到客户端
 41         new_client.send(response)
 42 
 43     # 关闭套接字 长链接不要关闭此套接字 等客户端关闭
 44     # new_client.close()
 45 
 46 
 47 def main():
 48     # 创建套接字
 49     tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 50     # 设置当服务器先调用close() 即服务器4次回收之后资源能够立即释放,这样就保证了下次运行程序时,可以立即使用
 51     # SO_REUSEADDR重复使用地址
 52     tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
 53     # 绑定端口
 54     tcp_server_socket.bind(("",7890))
 55     # 设置监听状态
 56     tcp_server_socket.listen(128)
 57     # 设置非堵塞
 58     tcp_server_socket.setblocking(False)
 59 
 60     # 创建一个epoll对象
 61     epl = select.epoll()
 62 
 63     # 将监听套接字对应的fd注册到epoll中
 64     # select.EPOLLIN监听是否有数据输入
 65     epl.register(tcp_server_socket.filno(),select.EPOLLIN)
 66 
 67     # 新建socket存储字典
 68     fd_event_dic = dict()
 69 
 70     # 新建为客户端服务的套接字
 71     while True:
 72         # poll()默认会堵塞 直到os监测到数据到来 通过事件通知方式 告诉这个程序 才会解堵塞  有返回值 返回值是列表
 73         fd_event_list = epl.poll()
 74 
 75         #[(fd,event),(套接字对应的文件描述符,这个文件描述符是什么事件 例如 可以调用recv()接收等)]
 76         for fd, event in fd_event_list:
 77             # 判断fd如果是监听套接字的fd
 78             if fd == tcp_server_socket.fileno():
 79                 # 创建客户端套接字,接收客户端地址
 80                 new_client, client_addr = tcp_server_socket.accept()
 81                 # 将客户端套接字fd注册到epoll中
 82                 epl.register(new_client.fileno(), select.EPOLLIN)
 83                 # 将客户端套接字存储到字典
 84                 fd_event_dic[new_client.fileno()] = new_client
 85                 # 如果不是监听套接字的fd或者是事件通知
 86             elif event == select.EPOLLIN:
 87                 recv_data = fd_event_dic[fd].recv(1024).decode("utf-8")
 88                 # 如果有数据
 89                 if recv_data:
 90                     # 调用client_server
 91                     client_server(fd_event_dic[fd], recv_data)
 92                     # 如果是空数据
 93                 else:
 94                     # 调用客户端套接字close()
 95                     fd_event_dic[fd].close()
 96                     # 注销在epoll中的客户端套接字fd
 97                     epl.unregister(fd)
 98                     # 移出字典
 99                     del fd_event_dic[fd]
100       
101 
102     # 关闭套接字
103     tcp_server_socket.close()
104 
105 
106 if __name__ == '__main__':
107     main()

猜你喜欢

转载自www.cnblogs.com/yifengs/p/11422789.html