Python进阶系列
Python进阶-网络编程-01
Python进阶-网络编程-02
Python进阶-网络编程-03
Python进阶-多任务编程-01
Python进阶-多任务编程-02
Python进阶-多任务编程-03
Python进阶-正则表达式
Python进阶-数据库编程-01
Python进阶-数据库编程-02
Python进阶-数据库编程-03
Python进阶-数据库编程-04
Python进阶-数据拷贝问题
Python进阶-模块导入问题
Python进阶-miniWeb框架
文章目录
5.1. 案例-模拟浏览器实现
-
步骤:
- 导入模块
- 创建套接字
- 建立连接
- 拼接请求协议
- 发送请求协议
- 接收服务器响应内容
- 保存内容
- 关闭连接
-
请求报文:
-
请求报文格式
-
请求行
- 请求方式 资源路径 协议及版本
\r\n
- 请求方式 资源路径 协议及版本
-
请求头
-
协议项
协议名:协议值
\r\n
-
-
请求空行
- 作用:分隔请求头和请求的主体
-
请求主体
- 浏览器要发给服务器的内容
- get方式没有请求体,post方式才有请求体
-
# 1.请求行 request_line = "GET / HTTP/1.1\r\n" # 2.请求头 request_header = "Host:www.icoderi.com\r\n" # 3.请求空行 request_blank = "\r\n" # 整体拼接 request_data = request_line + request_header + request_blank
-
-
代码实例:
# 1.导入模块 import socket # 2.创建套接字 tcp_client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 3.建立连接 tcp_client_socket.connect(("www.csdn.net",80)) # 4.拼接请求协议 # 请求行 request_line = "GET / HTTP1.1\r\n" # 请求头 request_header = "Host:www.csdn.net\r\n" # 请求空行 request_blank = "\r\n" # 整体拼接 request_data = request_line + request_header + request_blank # 5.发送请求协议 tcp_client_socket.send(request_data.encode()) # 6.接收服务器响应内容 recv_data = tcp_client_socket.recv(4096) recv_text = recv_data.decode() print(recv_text) # 7.保存内容 # 查询\r\n的位置 loc = recv_text.find("\r\n") # 截取字符串 html_data = recv_text[loc+4:] print(html_data) # 保存内容到文件中 with open("index.html","w") as file: file.write(html_data) # 8.关闭连接 tcp_client_socket.close()
5.2. 简单的web服务器
-
步骤:
- 导入模块
- 创建套接字
- 设置地址重用
- 绑定端口
- 设置监听,让套接字由主动变为被动接收
- 接受客户端连接定义函数request handler()
- 接收客户端浏览器发送的请求协议
- 判断协议是否为空
- 拼接响应的报文
- 发送响应报文
- 关闭操作
-
响应报文
-
响应报文格式
-
响应行
-
协议及版本 状态码 状态描述\r\n
常见的状态码
200 一切正常
404 客户端请求的资源不存在
302 重定向
-
-
响应头
-
协议项构成
协议名:协议值\r\n
-
-
响应空行
- 作用:分隔响应头和响应主体
-
响应主体
- 服务器响应给客户端的数据
# 响应行 response_line = "HTTP/1.1 200 OK\r\n" # 响应头 response_header = "Server:Python20WS/2.1\r\n" # 响应空行 response_blank = "\r\n" # 响应主体 response_body = "HelloPython!" response_data = response_line + response_header + response_blank + response_body
-
-
-
代码实例:
# 1.导入模块 import socket def request_handler(new_client_socket,ip_port): """接收信息,做出响应""" # 7.接收客户端浏览器发送的请求协议 request_data = new_client_socket.recv(1024) # 8.判断协议是否为空 if not request_data: print("%s客户端已经下线" % str(ip_port)) new_client_socket.close() return # 9.拼接响应的报文 # 响应行 response_line = "HTTP/1.1 200 OK\r\n" # 响应头 response_header = "Server:Python20WS/2.1\r\n" # 响应空行 response_blank = "\r\n" # 响应主体 response_body = "HelloPython!" response_data = response_line + response_header + response_blank + response_body # 10.发送响应报文 new_client_socket.send(response_data.encode()) # 11.关闭当前连接 new_client_socket.close() def main(): # 2.创建套接字 tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 3.设置地址重用 tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True) # 4.绑定端口(此时电脑的IP地址和端口(访问)) tcp_server_socket.bind(("192.168.16.64",8080)) # 5.设置监听,让套接字由主动变为被动接收 tcp_server_socket.listen(128) # 6.接受客户端连接 定义函数request handler() while True: new_client_socket,ip_port = tcp_server_socket.accept() # 调用函数处理请求并且响应 request_handler(new_client_socket,ip_port) # 11.关闭操作 tcp_server_socket.close() if __name__ == '__main__': main()
5.3. 简答的web服务器-返回固定页面
-
代码改动:
# 9、拼接响应的报文 # 响应行 response_line = "HTTP/1.1 200 OK\r\n" # 响应头 response_header = "Server:Python20WS/2.1\r\n" # 响应空行 response_blank = "\r\n" # 响应主体 with open("static/index.html","rb") as file: response_body = file.read() response_data = (response_line + response_header + response_blank).encode() + response_body
-
改动效果:
5.4. 简答的web服务器-返回指定页面
-
代码改动:
# 根据客户端浏览器请求的资源路径,返回请求资源 # <1> 把请求协议解码,得到请求报文的字符串 request_text = request_data.decode() # <2> 得到请求行 # 查找第一个\r\n出现的位置 loc = request_text.find("\r\n") # 截取字符串,从开头截取到第一个\r\n的位置 request_line = request_text[:loc] print(request_line) # <3> 把请求行,按照空格拆分,得到列表 request_line_list = request_line.split(" ") print(request_line_list) # 得到请求资源的路径 file_path = request_line_list[1] # 9、拼接响应的报文 # 响应行 response_line = "HTTP/1.1 200 OK\r\n" # 响应头 response_header = "Server:Python20WS/2.1\r\n" # 响应空行 response_blank = "\r\n" # 响应主体 # 拼接请求资源的路径 with open("static"+file_path,"rb") as file: response_body = file.read() response_data = (response_line + response_header + response_blank).encode() + response_body
-
改动效果:
5.5. 简答的web服务器-返回指定页面错误
-
代码改动:
# 响应主体 # 加入异常处理的判断,如果文件打开失败(即请求的资源路径不存在),程序会进入异常处理 # 在except中更响应主体的值,值就是错误类型 try: with open("static"+file_path,"rb") as file: response_body = file.read() except Exception as e: response_line = "HTTP/1.1 404 Not Found\r\n" response_body = ("Error!(%s)" % str(e)).encode() response_data = (response_line + response_header + response_blank).encode() + response_body
-
改动结果:
5.6. 简答的web服务器-面向对象封装
-
面向对象封装
import socket class WebServer(object): def __init__(self): # 2.创建套接字 self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 3.设置地址重用 self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 4.绑定端口 self.tcp_server_socket.bind(("", 8080)) # 5.设置监听,让套接字由主动变为被动接收 self.tcp_server_socket.listen(128) def start(self): # 6.接受客户端连接定义函数 request handler() while True: new_client_socket, ip_port = self.tcp_server_socket.accept() # 调用函数处理请求并且响应 self.request_handler(new_client_socket, ip_port) def request_handler(self,new_client_socket,ip_port): """接收信息,做出响应""" # 7.接收客户端浏览器发送的请求协议 request_data = new_client_socket.recv(1024) # 8.判断协议是否为空 if not request_data: print("%s客户端已经下线" % str(ip_port)) new_client_socket.close() return # 根据客户端浏览器请求的资源路径,返回请求资源 # <1> 把请求协议解码,得到请求报文的字符串 request_text = request_data.decode() # <2> 得到请求行 # 查找第一个\r\n出现的位置 loc = request_text.find("\r\n") # 截取字符串,从开头截取到第一个\r\n的位置 request_line = request_text[:loc] # <3> 把请求行,按照空格拆分,得到列表 request_line_list = request_line.split(" ") # 得到请求资源的路径 file_path = request_line_list[1] print("[%s]正在请求:%s" % (str(ip_port),file_path)) # 设置默认首页 if file_path == "/": file_path = "/index.html" # 9.拼接响应的报文 # 响应行 response_line = "HTTP/1.1 200 OK\r\n" # 响应头 response_header = "Server:Python20WS/2.1\r\n" # 响应空行 response_blank = "\r\n" # 响应主体 try: with open("static"+file_path,"rb") as file: response_body = file.read() except Exception as e: response_line = "HTTP/1.1 404 Not Found\r\n" response_body = ("Error!(%s)" % str(e)).encode() response_data = (response_line + response_header + response_blank).encode() + response_body # 10.发送响应报文 new_client_socket.send(response_data) # 11.关闭当前连接 new_client_socket.close() def main(): ws = WebServer() ws.start() if __name__ == '__main__': main()
5.7. 简答的web服务器-基础框架
-
模块1 简单的web服务器-基础框架.py
import socket from application import app class WebServer(object): def __init__(self): # 2.创建套接字 self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 3.设置地址重用 self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 4.绑定端口 self.tcp_server_socket.bind(("", 8080)) # 5.设置监听·让套接字由主动变为被动接收 self.tcp_server_socket.listen(128) def start(self): # 6.接受客户端连接定义函数request handler() while True: new_client_socket, ip_port = self.tcp_server_socket.accept() # 调用函数处理请求并且响应 self.request_handler(new_client_socket, ip_port) def request_handler(self,new_client_socket,ip_port): """接收信息,做出响应""" # 7.接收客户端刘觉器发送的请求协议 request_data = new_client_socket.recv(1024) # 8.判断协议是否为空 if not request_data: print("%s客户端已经下线" % str(ip_port)) new_client_socket.close() return # 使用appliocation文件夹app模块 application()处理 response_data = app.application("static",request_data,ip_port) # 10.发送响应报文 new_client_socket.send(response_data) # 11.关闭当前连接 new_client_socket.close() def main(): ws = WebServer() ws.start() if __name__ == '__main__': main()
-
模块2 app.py
from application import utils def parse_request(request_data,ip_port): # 根据客户端浏览器请求的资源路径,返回请求资源 # <1> 把请求协议解码,得到请求报文的字符串 request_text = request_data.decode() # <2> 得到请求行 # 查找第一个\r\n出现的位置 loc = request_text.find("\r\n") # 截取字符串,从开头截取到第一个\r\n的位置 request_line = request_text[:loc] # <3> 把请求行,按照空格拆分,得到列表 request_line_list = request_line.split(" ") # 得到请求资源的路径 file_path = request_line_list[1] print("[%s]正在请求:%s" % (str(ip_port), file_path)) # 设置默认首页 if file_path == "/": file_path = "/index.html" return file_path def application(current,request_data,ip_port): file_path = parse_request(request_data,ip_port) resource_path = current + file_path try: with open(resource_path, "rb") as file: response_body = file.read() response_data = utils.create_http_response("200 OK",response_body) except Exception as e: response_body = ("Error!(%s)" % str(e)).encode() response_data = utils.create_http_response("404 Not Found",response_body) return response_data
-
模块3 utils.py
def create_http_response(status,response_body): # 9.拼接响应的报文 # 响应行 response_line = "HTTP/1.1 %s\r\n" % status # 响应头 response_header = "Server:Python20WS/2.1\r\n" response_header = "Content-Type:text/html\r\n" # 响应空行 response_blank = "\r\n" # 响应主体 response_data = (response_line + response_header + response_blank).encode() + response_body return response_data