Web静态服务器
时间:2022-06-26
本文章向大家介绍Web静态服务器,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
1前情回顾
域名后面没有加端口,就是采用默认的端口。HTTP是80HTTPS是443
请求报文格式:请求行,请求头,空行,请求体。前三个每个后面都有rn
响应报文格式:响应行、响应头、空行、响应体。
状态码:2xx成功3xx重定向4xx客户端错误5xx服务器错误
HTTP协议用在浏览器和服务器之间
应用层协议
基于TCP
工作模式:一次请求,一次响应。多次请求,多次响应
提前将每个知识点过一遍
2 web服务器
2.1目的
理解一下web服务器的出路流程
将前面的知识融合起来
2.2介绍
简单扩充一下:
互联网:泛指一切可以互联互通的网络
因特网:偏向于网页、邮件之类的(不包括局域网)外网
万维网:特指浏览器和web服务器之间的
2.3 案例
2.3.1返回固定数据
注意:三引号是一个多行字符串,有注释的功能
"""
三引号是一个多行字符串,有注释的功能
"""
import socket
def main():
# 1创建套接字 绑定 监听套接字
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server_socket.bind(('',10086))
server_socket.listen(128)
while True:
# 2 不断接受连接
client_socket,client_addr = server_socket.accept()
print("接受到了来自%s的连接请求" % str(client_addr))
# 3 接收请求报文
request_data = client_socket.recv(4096).decode()
# 4 解析请求报文 得到用户的资源路径
# 5 读取对应资源 封装在http响应报文中发送给浏览器
response_line = 'HTTP/1.1 200 OKrn' # 响应行 状态行
# 如果想要显示中文 网页默认是gbk
# 加入'Content-Type: text/html;charset=UTF-8rn'
response_header = 'Server: BMW1.0rn' # 响应头
request_body = 'Hello Ethan yan' # 响应体
response_data = response_line + response_header +'rn'+request_body
client_socket.send(response_data.encode())
# 6 在合适的位置关闭套接字
client_socket.close()
if __name__ == '__main__':
main()
2.3.2返回固定网页
import socket
def main():
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
server_socket.bind(('',10010))
server_socket.listen(128)
while True:
client_socket,client_addr = server_socket.accept()
print("来自%s的最强王者上线了...." % str(client_addr))
request_data = client_socket.recv(4096).decode()
print("请求报文".center(30,'='))
print(request_data)
response_line = 'HTTP/1.1 200 OKrn'
response_header = 'Server: BMW1.0rn'+ 'Content-Type: text/html;charset=UTF-8rn'
# response_body = "来啦?老弟"
with open('index.html','rb') as file:
response_body = file.read()
response_data = (response_line + response_header + 'rn').encode() + response_body
client_socket.send(response_data)
client_socket.close()
if __name__ == '__main__':
main()
2.3.3返回指定网页
import socket
import re
def main():
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
server_socket.bind(('',10010))
server_socket.listen(128)
while True:
client_socket,client_addr = server_socket.accept()
print("来自%s的最强王者上线了...." % str(client_addr))
request_data = client_socket.recv(4096).decode()
if not request_data:
print("最强王者已经下限了")
client_socket.close()
continue
# GET /index2.html HTTP/1.1rn
# 切割请求报文 第0个元素就是请求行
# 连接的时候,浏览器会提前创建好几个链接
request_line = request_data.split('rn')[0]
# 从请求行中提取出用户的资源请求路径
result = re.match(r'w+s+(S+)',request_line)
if not result:
print("用户请求错误")
client_socket.close()
continue
print("用户的请求路径是%s" % result.group(1))
path_info = result.group(1)
# 当用户请求/ 表示首页 返回一个首页资源
if path_info == '/':
path_info = '/index.html'
response_line = 'HTTP/1.1 200 OKrn'
response_header = 'Server: BMW1.0rn'
# response_body = "来啦?老弟"
# 加'static'表示用户请求的路径都在这个路径下,从而保证系统的安全
with open('static'+path_info,'rb') as file:
response_body = file.read()
response_data = (response_line + response_header + 'rn').encode() + response_body
client_socket.send(response_data)
client_socket.close()
if __name__ == '__main__':
main()
2.3.4增加404页面
import socket
import re
import os
"""
web服务作用: 接收请求报文 返回网页资源给web浏览器
web服务器流程:
1 创建 绑定 监听套接字
2 接受连接
3 接收请求报文
4 解析请求报文 得到用户的资源请求路径
5 读取对应资源 封装在HTTP响应报文中发送给浏览器
6 在合适的位置关闭套接字即可
"""
def main():
# 1 创建 绑定 监听套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('', 9999))
server_socket.listen(128)
# 2 不断地接受连接
while True:
client_socket, client_addr = server_socket.accept()
print("接受到了来自%s的连接请求" % str(client_addr))
# 3 接收请求报文
request_data = client_socket.recv(4096).decode()
if not request_data:
print("用户已经断开连接了")
client_socket.close()
continue
# 4 解析请求报文 得到用户的资源请求路径 "GET /index2.html HTTP/1.1rn..."
# 4.1 切割请求报文 第0个元素就是请求行
request_line = request_data.split("rn")[0]
# 4.2 从请求行中提取出 用户资源请求路径
result = re.match(r"w+s+(S+)", request_line)
if not result:
print("用户请求格式错误")
client_socket.close()
continue
print("用户请求的路径是%s" % result.group(1)) # /home/python/Desktop/index.html
path_info = result.group(1)
# 当用户请求/ 表示首页 返回一个首页资源
if path_info == '/':
path_info = '/index.html'
response_header = "Server: PWS1.0rn" # 响应头
# 5 读取对应资源 封装在HTTP响应报文中发送给浏览器
if not os.path.exists("static" + path_info):
response_line = "HTTP/1.1 404 Not Foundrn"
with open("static/404.html","rb") as file:
response_body = file.read()
else:
response_line = "HTTP/1.1 200 OKrn" # 响应行 状态行
with open("static" + path_info, "rb") as file:
response_body = file.read()
response_data = (response_line + response_header + "rn").encode() + response_body
client_socket.send(response_data)
# 6 在合适的位置关闭套接字即可
client_socket.close()
文本文件二进制编码解码没有问题,但是如果是图片,就会出现问题
协程用在web
如果在发送文件的时候,有可能一次发送不完整,显示有误,可能是文件太大。我们可以将send方法改成sendall方法,即可解决
2.3.5 多任务
from gevent import monkey
monkey.patch_all() # 自动切换 recv accept time.sleep
import socket
import re
import os
import gevent
"""
web服务作用: 接收请求报文 返回网页资源给web浏览器
web服务器流程:
1 创建 绑定 监听套接字
2 接受连接
3 接收请求报文
4 解析请求报文 得到用户的资源请求路径
5 读取对应资源 封装在HTTP响应报文中发送给浏览器
6 在合适的位置关闭套接字即可
"""
def request_handler(client_socket):
"""这个函数用来处理客户端请求的"""
# 3 接收请求报文
request_data = client_socket.recv(4096).decode()
if not request_data:
print("最强王者已经下线了....")
client_socket.close()
return
# 4 解析请求报文 得到用户的资源请求路径 "GET /index2.html HTTP/1.1rn..."
# 4.1 切割请求报文 第0个元素就是请求行
request_line = request_data.split("rn")[0]
# 4.2 从请求行中提取出 用户资源请求路径
result = re.match(r"w+s+(S+)", request_line)
if not result:
print("用户请求格式错误")
client_socket.close()
return
print("用户请求的路径是%s" % result.group(1)) # /home/python/Desktop/index.html
path_info = result.group(1)
# 当用户请求/ 表示首页 返回一个首页资源
if path_info == '/':
path_info = '/index.html'
response_header = "Server: PWS1.0rn" # 响应头
# 5 读取对应资源 封装在HTTP响应报文中发送给浏览器
if not os.path.exists("static" + path_info):
response_line = "HTTP/1.1 404 Not Foundrn"
with open("static/404.html", "rb") as file:
response_body = file.read()
else:
response_line = "HTTP/1.1 200 OKrn" # 响应行 状态行
with open("static" + path_info, "rb") as file:
response_body = file.read()
response_data = (response_line + response_header + "rn").encode() + response_body
client_socket.sendall(response_data)
# 6 在合适的位置关闭套接字即可
client_socket.close()
def main():
# 1 创建 绑定 监听套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('', 9999))
server_socket.listen(128)
# 2 不断地接受连接
while True:
client_socket, client_addr = server_socket.accept()
print("来自%s的最强王者上线了...." % str(client_addr))
# 当收到用户请求时, 启动一个协程来运行下面的函数
gevent.spawn(request_handler,client_socket)
# spawn创建协程并启动
# request_handler(client_socket)
if __name__ == '__main__':
main()
2.3.6 面向对象
面向对象 每人的理解都不一样 面向对象 vs 面向过程 狗吃翔 吃狗翔
from gevent import monkey
monkey.patch_all() # 自动切换 recv accept time.sleep
import socket
import re
import os
import gevent
"""
web服务作用: 接收请求报文 返回网页资源给web浏览器
web服务器流程:
1 创建 绑定 监听套接字
2 接受连接
3 接收请求报文
4 解析请求报文 得到用户的资源请求路径
5 读取对应资源 封装在HTTP响应报文中发送给浏览器
6 在合适的位置关闭套接字即可
"""
class HTTPServer(object):
"""web服务器类"""
def __init__(self):
"""初始化 实例对象"""
# 1 创建 绑定 监听套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('', 9999))
server_socket.listen(128)
# 将套接字对象保存为当前对象
self.server_socket = server_socket
def start(self):
# 2 不断地接受连接
while True:
client_socket, client_addr = self.server_socket.accept()
print("来自%s的最强王者上线了...." % str(client_addr))
# 当收到用户请求时, 启动一个协程来运行下面的函数
gevent.spawn(self.request_handler, client_socket)
# spawn创建协程并启动
# request_handler(client_socket)
@staticmethod # 装饰器
def request_handler(client_socket):
"""这个函数用来处理客户端请求的"""
# 3 接收请求报文
request_data = client_socket.recv(4096).decode()
if not request_data:
print("最强王者已经下线了....")
client_socket.close()
return
# 4 解析请求报文 得到用户的资源请求路径 "GET /index2.html HTTP/1.1rn..."
# 4.1 切割请求报文 第0个元素就是请求行
request_line = request_data.split("rn")[0]
# 4.2 从请求行中提取出 用户资源请求路径
result = re.match(r"w+s+(S+)", request_line)
if not result:
print("用户请求格式错误")
client_socket.close()
return
print("用户请求的路径是%s" % result.group(1)) # /home/python/Desktop/index.html
path_info = result.group(1)
# 当用户请求/ 表示首页 返回一个首页资源
if path_info == '/':
path_info = '/index.html'
response_header = "Server: PWS1.0rn" # 响应头
# 5 读取对应资源 封装在HTTP响应报文中发送给浏览器
if not os.path.exists("static" + path_info):
response_line = "HTTP/1.1 404 Not Foundrn"
with open("static/404.html", "rb") as file:
response_body = file.read()
else:
response_line = "HTTP/1.1 200 OKrn" # 响应行 状态行
with open("static" + path_info, "rb") as file:
response_body = file.read()
response_data = (response_line + response_header + "rn").encode() + response_body
client_socket.sendall(response_data)
# 6 在合适的位置关闭套接字即可
client_socket.close()
def main():
# 创建出一个web服务器类的实例对象
http_server = HTTPServer()
# 启动服务器运行
http_server.start()
if __name__ == '__main__':
main()
# 面向对象 每人的理解都不一样
# 面向对象 vs 面向过程
# 狗吃翔 吃狗翔
2.3.7 给web服务器添加命令行参数
耦合 功能与功能之间的关联程度
开发:解耦合
高内聚,低耦合
独立性 依赖性
sys.argv里面存放的是当前进程启动时的命令行参数
sys.argv是列表,每个元素是字符串
系统将命令行参数放进去的
from gevent import monkey
monkey.patch_all() # 自动切换 recv accept time.sleep
import socket
import re
import os
import gevent
import sys
"""
web服务作用: 接收请求报文 返回网页资源给web浏览器
web服务器流程:
1 创建 绑定 监听套接字
2 接受连接
3 接收请求报文
4 解析请求报文 得到用户的资源请求路径
5 读取对应资源 封装在HTTP响应报文中发送给浏览器
6 在合适的位置关闭套接字即可
"""
class HTTPServer(object):
"""web服务器类"""
def __init__(self,port):
"""初始化 实例对象"""
# 1 创建 绑定 监听套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('',port))
server_socket.listen(128)
# 将套接字对象保存为当前对象
self.server_socket = server_socket
def start(self):
# 2 不断地接受连接
while True:
client_socket, client_addr = self.server_socket.accept()
print("来自%s的最强王者上线了...." % str(client_addr))
# 当收到用户请求时, 启动一个协程来运行下面的函数
gevent.spawn(self.request_handler, client_socket)
# spawn创建协程并启动
# request_handler(client_socket)
@staticmethod # 装饰器
def request_handler(client_socket):
"""这个函数用来处理客户端请求的"""
# 3 接收请求报文
request_data = client_socket.recv(4096).decode()
if not request_data:
print("最强王者已经下线了....")
client_socket.close()
return
# 4 解析请求报文 得到用户的资源请求路径 "GET /index2.html HTTP/1.1rn..."
# 4.1 切割请求报文 第0个元素就是请求行
request_line = request_data.split("rn")[0]
# 4.2 从请求行中提取出 用户资源请求路径
result = re.match(r"w+s+(S+)", request_line)
if not result:
print("用户请求格式错误")
client_socket.close()
return
print("用户请求的路径是%s" % result.group(1)) # /home/python/Desktop/index.html
path_info = result.group(1)
# 当用户请求/ 表示首页 返回一个首页资源
if path_info == '/':
path_info = '/index.html'
response_header = "Server: PWS1.0rn" # 响应头
# 5 读取对应资源 封装在HTTP响应报文中发送给浏览器
if not os.path.exists("static" + path_info):
response_line = "HTTP/1.1 404 Not Foundrn"
with open("static/404.html", "rb") as file:
response_body = file.read()
else:
response_line = "HTTP/1.1 200 OKrn" # 响应行 状态行
with open("static" + path_info, "rb") as file:
response_body = file.read()
response_data = (response_line + response_header + "rn").encode() + response_body
client_socket.sendall(response_data)
# 6 在合适的位置关闭套接字即可
client_socket.close()
def main():
# sys.argv对象 存储的是 当前进程运行的命令参数 的列表 每个元素都是字符串
# 如果说数量属于2个(缺端口) 或者 端口数据不是数字字符构成的
if len(sys.argv) < 2 or not sys.argv[1].isdigit():
print("参数使用错误 usage:python3 添加命令行参数指定端口.py 8888")
return
port = int(sys.argv[1])
# 创建出一个web服务器类的实例对象
http_server = HTTPServer(port)
# 启动服务器运行
http_server.start()
if __name__ == '__main__':
main()
- 关于CLR内存管理一些深层次的讨论[上篇]
- 关于CLR内存管理一些深层次的讨论[下篇]
- Python渗透工具的架构探讨
- 提供第三种代码生成方式——通过自定义BuildProvider为ASP.NET提供代码生成
- 小心,Android木马工具SpyNote免费啦!远程监听就是这么简单
- R语言的kmeans客户细分模型聚类
- .NET的资源并不限于.resx文件,你可以采用任意存储形式[下篇]
- 量化投资教程:用R语言打造量化分析平台
- 也谈事件(Event)
- Zuul:构建高可用网关之多维度限流
- Hystrix:HystrixCollapser请求合并
- oauth2.0 实现spring cloud nosession
- 基于自定义向导的C++单元测试环境自动化配置
- 【spring cloud】自定义jwt实现spring cloud nosession
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ABAP Debugging Script(调试器脚本)使用的一些实际例子
- MySQL 8.0新特性 — 事务性数据字典与原子DDL
- Python基础之面向对象-继承
- [源码分析]ArrayList和LinkedList如何实现的?我看你还有机会!
- 使用Python实现平台自动打卡
- QT学习第4天:qt点击鼠标画一条直线(附源代码和程序)
- 跨站请求伪造——CSRF
- 13-6 编辑多个文件和保存
- 汇编基础
- php 使用AMQP扩展调用RabbitMq
- 聊聊RedisTokenVisitor
- R语言几行代码拼接pdf文件
- 一次 Redis 分布式锁事故,整个项目组被扣绩效了。。。
- 小程序访问https显示网络错误,微信打开https空白、浏览器访问正常 解决方案
- Python GUI项目实战(七)学生信息的修改、删除和保存