web服务webserver

1.HTTP协议

  用途: 网页获取,数据的传输

  特点:   

  • 应用层协议,使用tcp进行数据传输

  • 简单,灵活,很多语言都有HTTP专门接口

  • 无状态,数据传输过程中不记录传输内容

  • 有丰富了请求类型

  • 可以传输的数据类型众多

网页访问流程

  客户端(浏览器)通过TCP传输,发送http请求给服务端

  服务端接收到http请求后进行解析

  服务端处理请求内容,组织响应内容

  服务端将响应内容以http响应格式发送给浏览器

  浏览器接收到响应内容,解析展示

HTTP请求

  请求行:具体的请求类别和请求内容

    GET         /        HTTP/1.1
    请求类别   请求内容     协议版本

    请求类别:每个请求类别表示要做不同的事情

        GET : 获取网络资源
        POST :提交一定的信息,得到反馈
        HEAD : 只获取网络资源的响应头
        PUT : 更新服务器资源
        DELETE : 删除服务器资源

  请求头:对请求的进一步解释和描述

Accept-Encoding: gzip

  空行

  请求体:请求参数或者提交内容

HTTP响应

  响应行:反馈基本的响应情况

HTTP/1.1     200       OK
版本信息    响应码   附加信息

  响应码:

1xx  提示信息,表示请求被接收
2xx  响应成功
3xx  响应需要进一步操作,重定向
4xx  客户端错误
5xx  服务器错误

  响应头:对响应内容的描述

Content-Type: text/html
Content-Length:109\r\n

  空行

  响应体:响应的主体内容信息

练习:主要功能 :

  【1】 接收客户端(浏览器)请求

  【2】 解析客户端发送的请求

  【3】 根据请求组织数据内容

  【4】 将数据内容形成http响应格式返回给浏览器

特点 :

  【1】 采用IO并发,可以满足多个客户端同时发起请求情况

  【2】 通过类接口形式进行功能封装

  【3】 做基本的请求解析,根据具体请求返回具体内容,同时可以满足客户端的网页效果加载

需求分析

技术点 : HTTP协议
         IO多路复用的并发网络模型

功能划分和封装: 类封装

协议 : http协议

逻辑实现步骤


功能性类 / 类接口

  socket()
     实例化对象 --> 不同的对象做些属性设置-->通信

  Process()/Thread()
     实例化对象 --> 绑定事件 --> 启动进程线程服务

  核心功能是干什么:网页分享
  使用流程:实例化对象 -> 启动服务
  传参 : 服务器地址  网页文件

  用户自己决定的是: 服务器地址  网页文件

逻辑步骤:
   tcp套接字
   搭建IO多路复用的并发模型
   接收客户端(浏览器)请求
   解析客户端发送的请求
   根据请求组织数据内容
   将数据内容形成http响应格式返回给浏览器

"""
web server 程序

完成一个类,提供给使用者
可以通过这个类快速搭建服务
完成网页展示
"""
from socket import *
from select import select
import re

# 封装所有web后端功能
class WebServer:
    def __init__(self, host="0.0.0.0", port=80, html=None):
        self.host = host
        self.port = port
        self.html = html
        self.rlist = []
        self.wlist = []
        self.xlist = []
        self.create_socket()
        self.bind()

    # 创建设置套接字
    def create_socket(self):
        self.sock = socket()
        self.sock.setblocking(False)

    # 绑定地址
    def bind(self):
        self.address = (self.host, self.port)
        self.sock.bind(self.address)

    # 启动整个服务
    def start(self):
        self.sock.listen(5)
        print("Listen the port %d" % self.port)
        # 先监控监听套接字
        self.rlist.append(self.sock)
        # 循环监控IO对象
        while True:
            rs, ws, xs = select(self.rlist, self.wlist, self.xlist)
            # 处理就绪的IO
            for r in rs:
                # 有客户端连接
                if r is self.sock:
                    connfd, addr = r.accept()
                    print("Connect from", addr)
                    # 将客户端连接套接字也监控起来
                    connfd.setblocking(False)
                    self.rlist.append(connfd)
                else:
                    # 处理浏览器端发的请求
                    try:
                        self.handle(r)
                    except:
                        pass
                    self.rlist.remove(r)
                    r.close()

    # 处理客户端请求
    def handle(self, connfd):
        # http请求
        request = connfd.recv(1024 * 10).decode()
        # 使用正则匹配请求内容
        pattern = r"[A-Z]+\s+(?P<info>/\S*)"
        result = re.match(pattern, request)
        if request:
            # 提取请求内容
            info = result.group("info")
            print("请求内容:",info)
            self.send_html(connfd,info)

    # 发送响应
    def send_html(self,connfd,info):
        # 对info分情况
        if info == "/":
            filename = self.html + "/index.html"
        else:
            filename = self.html + info

        # 打开判断文件是否存在
        try:
            file = open(filename,"rb")
        except:
            # 请求的网页不存在
            response = "HTTP/1.1 404 Not Found\r\n"
            response += "Content-Type:text/html\r\n"
            response += "\r\n"
            with open(self.html+"/404.html") as file:
                response += file.read()
            response = response.encode()
        else:
            # 请求的网页存在
            data = file.read() # 字节串
            response = "HTTP/1.1 200 OK\r\n"
            response += "Content-Type:text/html\r\n"
            response += "Content-Length:%d\r\n"%len(data)
            response += "\r\n"
            response = response.encode() + data
            file.close()
        finally:
            connfd.send(response)



if __name__ == '__main__':
    # 需要用户决定: 地址  网页
    httpd = WebServer(host="0.0.0.0",
                      port=8000,
                      html="./static")
    # 启动服务
    httpd.start()

 

 

 

 

 

posted @ 2020-10-26 19:12  Allin007  阅读(296)  评论(0)    收藏  举报