Http协议与静态web服务器学习

1.Http协议介绍

HTTP 协议 全程,中文超文本传输协议
超文本是超级文本的缩写,是指超越文本限制或超链接,比如:图片、音乐、视频、超链接等都属于超文本
HTTP (1991)设计的目的:传输网页数据,现在允许传输任意类型的数据
传输HTTP协议(通信数据的格式)格式的数据是基于TCP 传输协议的,发送数据之前先建立连接

  1. HTTP协议的作用
    它规定了浏览器和Web服务器通信数据的格式,也就是说浏览器和web服务器通信需要使用http协议

  2. 浏览器访问web服务器的通信过程
    web服务器程序默认端口号为80

    1. 浏览器输入网址–通过DNS(域名解析服务器)将域名解析成ip地址
    2. 客户端获取到ip地址,端口号(web服务程序默认端口号为80)
    3. 与web服务器程序建立连接(HTTP是基于TCP的)
    4. 发送http请求数据到web服务器程序(http格式的数据)
    5. web服务器根据请求获取本地服务器主机资源
    6. 本地服务器主机返回资源到web服务器
    7. web服务器返回http响应数据到浏览器

2.URL

URL 表达的是统一资源定位符,通俗讲就是网络资源地址,也是常说的网址

  1. URL组成:
    1. 样式:https://news.163.com/18/1122/10/E178J2O.html
    2. 协议部分:https:// (会对http://的数据进行加密 端口号 443) http://(端口号为80) ftg://
    3. 域名部分:news.163.com
    4. 资源路径:18、/34fds3245fs.html
    5. 查询参数部分(可选)
  2. 域名就是ip地址的别名,是用点进行分割使用英文字母和数字组成的名字,使用域名目的就是方便记忆某台ip地址
  3. url https://news.163.com/heellooe.html?page=1&count=10
    1. ? 后面的参数 都 使用& 连接

3.HTTP请求报文

  1. http请求报文(浏览器发送给web服务器程序的http协议数据)
    1. http最常见的请求报文有两种:
      1. GET 方式请求报文 获取web服务器数据 如:新闻列表
      2. POST 方式请求报文 向web服务器提交数据以及获取数据 如:登录
  2. HTTP GET 请求报文
    1. 格式:
      1. 请求行 \r\n
      2. 请求头 、\r\n
      3. 空行 \r\n
      4. 每项信息之间都需要一个 \r\n ,不能有空格,要http协议规定
    2. 请求报文 请求头–请求行–空行
      1. GET/HTTP/1.2 请求方式 请求资源路径 http协议版本
      2. HOST: 服务器主机ip地址和端口号,默认端口号是80
      3. Connection:Keep-alive 和服务端操持长链接,当客户端和服务端有一段时间(3-5)没有进行通信,服务器程序就会主动向客户端断开连接
      4. Upgrade-Insecure-Requests:1 让客户端请求不安全请求,以后会用https
      5. User-Agent 用户代理,客户端程序名称,
      6. Accept 告诉服务端程序可以接受的数据类型
      7. Accept-Encoding: 告诉服务端程序支持的压缩算法
      8. Accept-Language: 告诉服务端程序支持的语言
      9. Cookie 客户端用户身份的标识(唯一的)
  3. HTTP POST 请求报文
    1. GET 请求格式
    2. Form Data 请求体,浏览器发送给服务器的数据(可以没有但很少)
  4. HTTP 响应报文(服务端程序传过来的数据)响应行–响应头–空行–响应体
    1. HTTP/1.1 200 OK HTTP协议版本 状态码 状态描述(响应行)
    2. Server 服务器的名称
    3. Content-Type 服务器发送给浏览器的内容类型及编码格式
    4. Transfer-Encoding 服务器发送给客户端程序(浏览器)的数据不确定数据长度 数据发送结束的接收标识 :0\r\n Content-Length:200(字段) 服务器发送给客户端程序的数据确定长度
    5. Connection :Keep-alive 和客户端保持长连接
    6. Data 服务器的时间 (0时区时间 北京是东八区 差8个小时)
    7. 剩下是自定义响应头信息,自己定义响应头的名字和响应头的信息
    8. —空行—
    9. —响应体—
    10. 每一项都有 \r\n
    11. –响应体 就是真正意义上给浏览器解析使用的数据–(Response里的)
    12. 对于请求头和响应头信息程序员都可以自定义,按照客户端和服务器约定好的发方式进行来判定即可
  5. 状态码(用于标识web服务器响应状态的3位数字代码)
    1. 200 请求成功
    2. 307 重定向
    3. 400 错误请求,请求地址或者参数有误
    4. 404 请求资源在服务器不存在
    5. 500 服务器内部资源代码出现错误

4.搭建Python自带静态Web服务器

  1. 静态Web服务器是什么?
    可以为发出请求的浏览器提供静态文档的程序,
    我们平时浏览百度新闻数据的时候,每天的新闻数据都是会发生变化,此访问的页面就是动态的,而我们开发的是静态的,页面的数据不会发生改变
  2. 如何搭建Python自带的静态Web服务器
    1. 搭建Python自带的静态Web服务器 使用 python3 -m http.server 端口号(默认是8000)
    2. -m 表示运行包里面的模块,执行这个命令的时候,需要进入自己指定的静态文件的目录,然后通过浏览器就能访问对应的html 文件了,这样一个静态的Web服务器就搭建好了

5.搭建自己的静态Web服务器

  1. 步骤
    1. 编写一个TCP服务端程序
    2. 获取浏览器发送的http请求报文数据
    3. 读取固定页面的数据,把页面数据组装成HTTP响应报文数据发送给浏览器
    4. HTTP响应报文数据发送完成后,关闭服务于客户端的套接字
  2. 搭建静态Web服务器–返回固定页面数据
    1. 创建服务端套接字对象
    2. 设置服务端套接字复用
    3. 绑定端口号
    4. 设置监听(最大监听数为128)
    5. 等待接收客户端连接请求,拿到客户端传来的通信套接字 (循环等待)
    6. 接收客户端的请求想信息 (数据量大概在4k多)
    7. with open 打开文件 读取数据(文件路径为html 文件路径,encoding=‘utf-8’(可选))
    8. 响应行 response_line=‘HTTP协议版本 状态码 状态描述 \r\n’
    9. 响应头 response_header=‘Server: 服务器名称(一般为python的) \r\n’
    10. 空行
    11. 响应体 response_body=f_data(读物到的文件中数据)
    12. 把数据封装成http 响应报文的数据格式 response=response_line+response_header+’\r\n’+response_body
    13. 将字符串编码为二进制 response_data=response.encode(‘utf-8’)
    14. 将响应报文数据发送给浏览器 new_socket.send(response_data)
    15. 关闭客户端套接字
import socket
#判断是否主模块
if __name__=='__main__':
    #创建tcp服务端套接字
    tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #设置端口号复用
    tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
    #绑定套接字端口号
    tcp_server_socket.bind(('',8000))
    #设置监听 最大监听数
    tcp_server_socket.listen(128)
    while True:
        #等待连接
        new_socket,iport=tcp_server_socket.accept()
        # print('收到端口号为',iport)
        #接收客户端请求信息
        recv_data=new_socket.recv(4096)
        print(recv_data)
        #打开文件读取数据 with opne 系统榜我们关闭文件
        with open('wenjian/templates/index.html',encoding='utf-8') as f:
            f_data=f.read()
        #把数据封装成http 响应报文格式的数据
       	#响应行
        response_line='HTTP/2 200 OK\r\n'
        #响应头
        response_header='Server: PWS/2.0\r\n'
        #空行
   	 	#响应体
        response_body=f_data
       	#把数据封装成http 响应报文格式的数据
       	response=response_line+response_header+'\r\n'+response_body
        #把字符串编码成二进制
        response_data=response.encode('utf-8')
        #发送给浏览器的响应报文数据
        new_socket.send(response_data)
        #关闭服务于客户端的套接字
        new_socket.close()

6.静态服务器-返回指定页面内容

  1. 创建服务端套接字对象
  2. 设置端口号复用
  3. 绑定端口号
  4. 设置监听
  5. 等待客户端连接请求 得到新的通信套接字 (循环保持服务长启)
  6. 接收客户端的请求信息 并对之解码 (需要判断接收的数据长度是否为0,防止客户端不发送信息,造成服务器奔溃)(请求报文的请求头有页面信息)
  7. 利用空格分割得到指定页面名称
  8. 打开指定文件(为图片能够加载 使用 rb 模式)(判断客户端请求是否为根目录,设置默认值)
  9. 响应行
  10. 响应头
  11. 空行
  12. 响应体=文件读取的数据
  13. 将数据封装成 http 格式 并转换为字节码格式
  14. 发送http协议数据
  15. 关闭客户端套接字
'''返回指定页面数据'''
import socket
def main():
    #1.创建服务端套接字
    tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #设置套接字复印
    tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
    #3.绑定端口号
    tcp_server_socket.bind(('',8000))
    #4.设置监听
    tcp_server_socket.listen(128)
    while True:
        #等待客户端连接请求
        new_socket,iport=tcp_server_socket.accept()
        #接收客户端请求数据
        recv_data_en=new_socket.recv(4096)
        if len(recv_data_en) == 0:
            new_socket.close()
            return
        #将接收的数据解码
        recv_data=recv_data_en.decode('utf-8')
        #将解码的字符串 空格分割 得到请求的指定页面信息
        recv_data_list=recv_data.split(' ',maxsplit=2)
        request_path=recv_data_list[1]
        print(request_path)
        # 判断当亲戚去为 / 默认为index 文件
        if request_path=='/':
            request_path='/index.html'
        #打开相应文件读取信息 使用rb兼容打开图片
        with open('wenjian'+request_path,'rb') as f:
            f_data=f.read()
        #响应行
        response_line='HTTP/2 200 OK\r\n'
        # 响应头
        response_header='Server: PWS/2.0\r\n'
        #空行
        #响应体
        response_body=f_data
        #经数据封装成http 格式数据
        response=(response_line+response_header+'\r\n').encode('utf-8')+response_body
        # 发送数据
        new_socket.send(response)
        #关闭客户端套接字
        new_socket.close()
if __name__ == '__main__':
    main()

7.返回404页面

在原有基础上添加 判断请求页面是否存在

  1. 通过os.path.exits
  2. 通过异常处理
'''返回404'''
import socket
import os
def main():
    #创建服务端套接字对象
    tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #设置端口号复用
    tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
    # 绑定端口号
    tcp_server_socket.bind(('',8000))
    #设置监听
    tcp_server_socket.listen(128)
    while True:
        # 等待客户端连接请求
        new_socket,iport=tcp_server_socket.accept()
        recv_data=new_socket.recv(4096)
        if len(recv_data)==0:
            new_socket.close()
            return
        #解码
        recv_datam=recv_data.decode('utf-8')
        #拿到客户端请求的页面名称
        request_li=recv_datam.split(' ',maxsplit=2)
        request=request_li[1]
        if request=='/':
            request='/index.html'
        print(request)
        #1.os.path.exits
        #2.try-except
        #打开页面文件
        try:
            with open('wenjian'+request,'rb') as f:
                f_data=f.read()
        except Exception as e:
            #找不到页面
            # 响应行
            response_line = 'HTTP/2 404 Not Found\r\n'
            # 响应头
            response_header = 'Server PWS/2.0\r\n'
            # 空行
            # 响应体
            with open('wenjian/error.html',encoding='utf-8') as f:
                f_data=f.read()
            response_body=f_data
            # 封装http 数据
            response = response_line + response_header + '\r\n'+ response_body
            # 发送数据
            new_socket.send(response.encode('utf-8'))
        else:
            #响应行
            response_line='HTTP/2 200 OK\r\n'
            #响应头
            response_header='Server PWS/2.0\r\n'
            #空行
            #响应体
            response_body=f_data
            #封装http 数据
            response=(response_line+response_header+'\r\n').encode('utf-8')+response_body
            #发送数据
            new_socket.send(response)
        finally:
            #关闭客户端套接字
            new_socket.close()
if __name__ == '__main__':
    main()

8.多任务

通过应用线程

'''多任务'''
import socket,os,threading
def th_accept(new_socket):
    # 接收客户端传来的数据
    recv_data = new_socket.recv(4096)
    # 判断数据是否为空
    if len(recv_data) == 0:
        new_socket.close()
        return
    # 解码
    recv_d = recv_data.decode('utf-8')
    # 分割请求报文信息
    recv_li = recv_d.split(' ', 2)
    # 得到请求页名称
    request = recv_li[1]
    if request == '/':
        request = '/index.html'
    # 判断 请求页数据是否存在
    if not os.path.exists('wenjian' + request):
        with open('wenjian/error.html', encoding='utf-8') as f:
            f_data = f.read()
        # 响应行
        response_line = 'HTTP/2 404 Not Found\r\n'
        # 响应头
        response_header = 'Server PWS/2.0\r\n'
        # 空行
        # 响应体
        response_body = f_data
        # 封装数据
        response = response_line + response_header + '\r\n' + response_body
        # 发送编码的数据
        new_socket.send(response.encode('utf-8'))
        new_socket.close()
    else:
        with open('wenjian' + request, 'rb') as f:
            f_data = f.read()
            # 响应行
            response_line = 'HTTP/2 200 OK\r\n'
            # 响应头
            response_header = 'Server PWS/2.0\r\n'
            # 空行
            # 响应体
            response_body = f_data
            # 封装数据
            response = (response_line + response_header + '\r\n').encode('utf-8') + response_body
            # 发送编码的数据
            new_socket.send(response)
            # 关闭客户端套接字
            new_socket.close()
def main():
    #创建服务端套接字对象
    tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #设置端口号复用
    tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
    #绑定端口号
    tcp_server_socket.bind(('',8000))
    #设置监听
    tcp_server_socket.listen(128)
    while True:
        #等待客户端连接请求
        new_socket,iport=tcp_server_socket.accept()
        #创建子线程
        sub_thread=threading.Thread(target=th_accept,args=(new_socket,),daemon=True)
        # 启动子线程
        sub_thread.start()
if __name__ == '__main__':
    main()

9.面向对象开发

  1. 步骤
    1. 把提供服务的web服务器抽象成一个类(HTTPWebServer)
    2. 提供Web服务器的初始化方法,在初始化方法里面创建socket对象
    3. 提供一个开启web服务器的方法,让Web服务器处理客户端请求
'''面向对象的'''
import socket,os,threading
#HTTPWebServer 列
class HttpWebServer(object):
    def __init__(self):
        #创建服务端套接字对象
        tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        #设置端口号复用
        tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
        #绑定的端口号
        tcp_server_socket.bind(('',8000))
        #设置监听
        tcp_server_socket.listen(128)
        #把服务器的套接字作为web服务器对象的属性
        self.tcp_server_socket=tcp_server_socket
    @staticmethod
    def th_accept(new_socket):
        # 接收客户端传来的数据
        recv_data = new_socket.recv(4096)
        # 判断数据是否为空
        if len(recv_data) == 0:
            new_socket.close()
            return
        # 解码
        recv_d = recv_data.decode('utf-8')
        # 分割请求报文信息
        recv_li = recv_d.split(' ', 2)
        # 得到请求页名称
        request = recv_li[1]
        if request == '/':
            request = '/index.html'
        # 判断 请求页数据是否存在
        if not os.path.exists('wenjian' + request):
            with open('wenjian/error.html', encoding='utf-8') as f:
                f_data = f.read()
            # 响应行
            response_line = 'HTTP/2 404 Not Found\r\n'
            # 响应头
            response_header = 'Server PWS/2.0\r\n'
            # 空行
            # 响应体
            response_body = f_data
            # 封装数据
            response = response_line + response_header + '\r\n' + response_body
            # 发送编码的数据
            new_socket.send(response.encode('utf-8'))
            new_socket.close()
        else:
            with open('wenjian' + request, 'rb') as f:
                f_data = f.read()
                # 响应行
                response_line = 'HTTP/2 200 OK\r\n'
                # 响应头
                response_header = 'Server PWS/2.0\r\n'
                # 空行
                # 响应体
                response_body = f_data
                # 封装数据
                response = (response_line + response_header + '\r\n').encode('utf-8') + response_body
                # 发送编码的数据
                new_socket.send(response)
                # 关闭客户端套接字
                new_socket.close()

    #启动服务器
    def start(self):
        while True:
            # 等待客户端连接请求
            new_socket, iport = self.tcp_server_socket.accept()
            # 创建子线程
            sub_thread = threading.Thread(target=self.th_accept, args=(new_socket,), daemon=True)
            # 启动子线程
            sub_thread.start()
def main():
    #创建web 防御武器
    web_server=HttpWebServer()
    # 启动服务器
    web_server.start()
if __name__ == '__main__':
    main()

10.获取终端命令行参数及启动动态绑定端口号

使用sys模块
params=sys.argv
print(params) #是列表形式

  1. 步骤
    1. 获取执行python程序的终端命令行参数
    2. 判断参数的类型,设置端口号必须是整形
    3. 给web服务器类初始化方法添加一个动态端口号参数,用于绑定端口号
    4. linux 终端启动 用Python3
    5. windows 终端启动 用Python(在文件目录下)
import sys
import socket,os,threading
#HTTPWebServer 列
class HttpWebServer(object):
    def __init__(self,port):
        #创建服务端套接字对象
        tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        #设置端口号复用
        tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
        #绑定的端口号
        tcp_server_socket.bind(('',port))
        #设置监听
        tcp_server_socket.listen(128)
        #把服务器的套接字作为web服务器对象的属性
        self.tcp_server_socket=tcp_server_socket
    @staticmethod
    def th_accept(new_socket):
        # 接收客户端传来的数据
        recv_data = new_socket.recv(4096)
        # 判断数据是否为空
        if len(recv_data) == 0:
            new_socket.close()
            return
        # 解码
        recv_d = recv_data.decode('utf-8')
        # 分割请求报文信息
        recv_li = recv_d.split(' ', 2)
        # 得到请求页名称
        request = recv_li[1]
        if request == '/':
            request = '/index.html'
        # 判断 请求页数据是否存在
        if not os.path.exists('wenjian' + request):
            with open('wenjian/error.html', encoding='utf-8') as f:
                f_data = f.read()
            # 响应行
            response_line = 'HTTP/2 404 Not Found\r\n'
            # 响应头
            response_header = 'Server PWS/2.0\r\n'
            # 空行
            # 响应体
            response_body = f_data
            # 封装数据
            response = response_line + response_header + '\r\n' + response_body
            # 发送编码的数据
            new_socket.send(response.encode('utf-8'))
            new_socket.close()
        else:
            with open('wenjian' + request, 'rb') as f:
                f_data = f.read()
                # 响应行
                response_line = 'HTTP/2 200 OK\r\n'
                # 响应头
                response_header = 'Server PWS/2.0\r\n'
                # 空行
                # 响应体
                response_body = f_data
                # 封装数据
                response = (response_line + response_header + '\r\n').encode('utf-8') + response_body
                # 发送编码的数据
                new_socket.send(response)
                # 关闭客户端套接字
                new_socket.close()

    #启动服务器
    def start(self):
        while True:
            # 等待客户端连接请求
            new_socket, iport = self.tcp_server_socket.accept()
            # 创建子线程
            sub_thread = threading.Thread(target=self.th_accept, args=(new_socket,), daemon=True)
            # 启动子线程
            sub_thread.start()
def main():
    #获取命令行参数
    params=sys.argv
    if len(params)!=2:#只能输入两个参数
        print('执行命令格式:python3 xxx.py 9000')
        return
    if not params[1].isdigit():#不是数字
        print('执行命令格式:python3 xxx.py 9000')
        return
    port=int(params[1])
    print(params)
    #创建web 防御武器
    web_server=HttpWebServer(port)
    # 启动服务器
    web_server.start()
if __name__ == '__main__':
    main()



  • 没有伤痕累累,哪有皮糟肉厚
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值