zoukankan      html  css  js  c++  java
  • Webserver-HTTP项目(深入理解HTTP协议)

    # HTTP项目实战
    - 深入理解HTTP协议
    - 模拟后台服务程序基本流程和大致框架
    - 每一个步骤一个文件夹
    - 图解http协议, 图解tcp/ip协议

    # v01-验证技术
    - 验证socket-tcp技术,看能否走通流程
    - 使用浏览器发送消息,访问地址

    # V02-解析传入http协议
    - 根据http协议格式,逐行读取信息
    - 按行读取后的信息,需要进行拆解,

    # 推荐书籍
    - 日本人写的 图解Http"
    - 图解系列严重推荐

    # v03-http协议封装返回内容
    - 返回头: "HTTP/1.1 200 OK "
    - 首部行:
    - "Content-Length: xxx "
    - "Date: 20180616 "
    - 空行:
    - " "
    - 返回内容:
    - "I love beijign tulingxueyuan"
    - 例子v03

    # v04-面向对象重构
    - 两个对象:
    - 一个负责监听接受传入socketWebServer
    - 一个负责通讯, SocketHandler
    - 参看例子v04

    # v05-使用配置文件

    # v06-返回静态页面
    - 静态文件:不常编辑的文件内容
    - 静态文件的存储: 一般单独放入一共文件夹,或者静态文件服务器
    - 需要有一共html类型的页面
    - html文件作为文件读入内容
    - 作为结果反馈回去
    - 静态文件存放再: webapp文件夹下

    # v07-添加路由功能和404
    - 路由: 能够理解请求并按照请求调用相应处理函数的模块
    - 理解请求内容
    - 能够调用或者指定相应业务处理模块
    - 算法:
    - 按行读取传入报文
    - 假如报文能用空格分割成三段,则是请求行
    - 否则,是首部行,首部行必须要能够用冒号空格分割成两段
    - 首部行是天然的键值对
    - 请求行需要自行增加键
    - 404代表访问的资源不存在

    # v08-添加静态文件
    - 静态文件: web后台,一般把图片,音频,视频,附件等很少需要更改内容的文件成为静态文件
    - 新建文件夹static用来存放静态文件



    ========================================
    TCP传输+HTTP协议
     
    HTTP协议请求头部:
     
    HTTP头部解析算法:
     
    添加路由:
    一个socket负责通道传输,一个socket负责监听,其他的socket负责处理;
    socker并发执行。

    v01-验证技术:
    import socket

    # 理解两个参数的含义
    # 理解创建一个socket的过程
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 注意addr的格式是tuple
    # 以及tuple两个元素的含义
    sock.bind(("127.0.0.1", 7852))
    print("已经绑定端口........")
    # 监听
    sock.listen()
    print("正在监听......")

    # 接受一个传进来的socket
    print("准备接受socket传入....")
    skt, addr = sock.accept()
    print("已经接收到传入socket {0}".format(skt))

    # 读取传入消息,实际上是信息
    # 需要注意读取的信息的长度一定要小于等于实际消息的长度,否则会假死
    msg = skt.recv(100)
    print(type(msg))

    # decode默认utf-8
    print(msg.decode())


    # 给对方一个反馈
    msg = "I love only wangxiaojing"
    skt.send(msg.encode())

    skt.close()
    sock.close()


    解析传入HTTP:
    import socket



    def getHttpHeader(skt):
    '''
    得到传入sockethttp请求头
    :param skt: 通信的socket
    :return: 解析后的请求头内容,字典形式
    '''

    # 读取某一行
    # 直到读取的行返回空行为止

    # 用来存放结果,dict类型
    rst = {}

    line = getLine(skt)
    while line:
    '''
    判断得到的行是报头还是首部行,两个操作方法不一样
    算法是:
    1. 利用作为分隔符,分割字符串
    2. 如果是首部行,则一定会把字符串分成两个子串
    3. 否则就是一个字符串
    '''
    r = line.split(r': ')

    if len(r) == 2:
    rst[r[0]] = r[1]
    else:
    r = line.split(r' ')
    rst['method'] = r[0]
    rst['uri'] = r[1]
    rst['version'] = r[2]

    line = getLine(skt)

    return rst




    def getLine(skt):
    '''
    socket中读取某一行
    :param skt: ocket
    :return: 返回读取到的一行str格式内容
    '''
    '''
    前提:
    1. http协议传输内容是ascii编码
    2. 真正传输的内容是通过网络流传输
    3. 回车换行: b' ', b' ', b表示是一个bytes格式
    '''
    # 每次从socket读取一个byte内容
    b1 = skt.recv(1)
    b2 = 0
    #data用来存放读取的行的内容
    data = b''

    #当确定还没有读到一行最后,也就是回车换行符号的时候,需要循环
    while b2 != b' ' and b1 != b' ':
    b2 = b1
    b1 = skt.recv(1)

    data += bytes(b2)

    # decode 需要一个参数,即编码,但是不给的话就采用默认utf-8解码
    return data.strip(b' ').decode()


    # 理解两个参数的含义
    # 理解创建一个socket的过程
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 注意addr的格式是tuple
    # 以及tuple两个元素的含义
    sock.bind(("127.0.0.1", 7852))
    print("已经绑定端口........")
    # 监听
    sock.listen()
    print("正在监听......")

    # 接受一个传进来的socket
    print("准备接受socket传入....")
    skt, addr = sock.accept()
    print("已经接收到传入socket {0}".format(skt))

    # 实际处理请求内容
    http_info = getHttpHeader(skt)
    print(http_info)




    # 给对方一个反馈
    msg = "I love only wangxiaojing"
    skt.send(msg.encode())

    skt.close()
    sock.close()


    v03-HTTP协议返回:
    import socket



    def getHttpHeader(skt):
    '''
    得到传入sockethttp请求头
    :param skt: 通信的socket
    :return: 解析后的请求头内容,字典形式
    '''

    # 读取某一行
    # 直到读取的行返回空行为止

    # 用来存放结果,dict类型
    rst = {}

    line = getLine(skt)
    while line:
    '''
    判断得到的行是报头还是首部行,两个操作方法不一样
    算法是:
    1. 利用作为分隔符,分割字符串
    2. 如果是首部行,则一定会把字符串分成两个子串
    3. 否则就是一个字符串
    '''
    r = line.split(r': ')

    if len(r) == 2:
    rst[r[0]] = r[1]
    else:
    r = line.split(r' ')
    rst['method'] = r[0]
    rst['uri'] = r[1]
    rst['version'] = r[2]

    line = getLine(skt)

    return rst




    def getLine(skt):
    '''
    socket中读取某一行
    :param skt: ocket
    :return: 返回读取到的一行str格式内容
    '''
    '''
    前提:
    1. http协议传输内容是ascii编码
    2. 真正传输的内容是通过网络流传输
    3. 回车换行: b' ', b' ', b表示是一个bytes格式
    '''
    # 每次从socket读取一个byte内容
    b1 = skt.recv(1)
    b2 = 0
    #data用来存放读取的行的内容
    data = b''

    #当确定还没有读到一行最后,也就是回车换行符号的时候,需要循环
    while b2 != b' ' and b1 != b' ':
    b2 = b1
    b1 = skt.recv(1)

    data += bytes(b2)

    # decode 需要一个参数,即编码,但是不给的话就采用默认utf-8解码
    return data.strip(b' ').decode()



    def sendRsp(skt, content):
    '''
    发送返回值,利用传入的socket
    :param skt: 通信的socket
    :return:
    '''

    # 构建返回头
    rsp_1 = "HTTP/1.1 200 OK "
    rsp_2 = "Date: 20180616 "
    # 求返回内容的长度
    len_value= len(content)
    rsp_3 = "Content-Length: {0} ".format(len_value)
    rsp_4 = " "
    rsp_content = content
    # rsp代表返回的全部数据信息,里面包含http协议本身的内容
    rsp = rsp_1 + rsp_2 + rsp_3 + rsp_4 + rsp_content

    skt.send(rsp.encode())



    # 理解两个参数的含义
    # 理解创建一个socket的过程
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 注意addr的格式是tuple
    # 以及tuple两个元素的含义
    sock.bind(("127.0.0.1", 7852))
    print("已经绑定端口........")
    # 监听
    sock.listen()
    print("正在监听......")

    # 接受一个传进来的socket
    print("准备接受socket传入....")
    skt, addr = sock.accept()
    print("已经接收到传入socket {0}".format(skt))

    # 实际处理请求内容
    http_info = getHttpHeader(skt)
    print(http_info)




    # 给对方一个反馈
    msg = "I love only wangxiaojing"
    sendRsp(skt, msg)

    skt.close()
    sock.close()


    v04-OOP重构-面向对象重构代码
    import socket
    import threading

    class SocketHandler:

    def __init__(self, sock):
    self.sock = sock
    # 放置Http请求的头部信息
    self.headInfo = set()

    def startHandler(self):
    '''
    处理传入请求做两件事情
    1. 解析http协议
    2. 返回n内容
    :return:
    '''
    self.headHandler()
    self.sendRsp()
    return None

    def headHandler(self):
    # 两个下划线开头的变量是啥意思捏?
    self.headInfo = self.__getAllLine()
    print(self.headInfo)
    return None

    def sendRsp(self):
    data = "HELLO WORLD"
    self.__sendRspAll(data)
    return None

    #####################################

    def __getLine(self):

    b1 = self.sock.recv(1)
    b2 = 0
    data = b''

    while b2 != b' ' and b1 != b' ' :
    b2 = b1
    b1 = self.sock.recv(1)

    data += bytes(b2)

    return data.strip(b' ')


    def __getAllLine(self):

    data = b''
    dataList = list()
    data = b''

    while True:
    data = self.__getLine()
    if data:
    dataList.append(data)
    else:
    return dataList

    return None

    def __sendRspLine(self,data):

    data += " "
    self.sock.send(data.encode("ASCII"))
    return None


    def __sendRspAll(self, data):

    self.__sendRspLine("HTTP/1.1 200 OK")

    strRsp = "Content-Length: "
    strRsp += str(len(data))
    self.__sendRspLine( strRsp )

    self.__sendRspLine("Content-Type: text/html")

    self.__sendRspLine("")
    self.__sendRspLine(data)


    class WebServer():


    def __init__(self, ip='127.0.0.1', port=7853):
    self.ip = ip
    self.port = port

    self.sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
    self.sock.bind((self.ip, self.port))
    self.sock.listen(1)
    print("WebServer is started............................")

    def start(self):
    '''
    服务器程序一共永久性不间断提供服务
    :return:
    '''
    while True:
    skt, addr = self.sock.accept()

    if skt:
    print("Received a socket {0} from {1} ................. ".format(skt.getpeername(), addr))
    # sockHandler负责具体通信
    sockHandler = SocketHandler(skt)
    thr = threading.Thread(target=sockHandler.startHandler , args=( ) )
    thr.setDaemon(True)
    thr.start()
    thr.join()

    skt.close()
    print("Socket {0} handling is done............".format(addr))



    if __name__ == '__main__':
    ws = WebServer()
    ws.start()

    v05-配置文件
    class ServerContent:
    ip = '127.0.0.1'
    port = 9999

    head_protocal = "HTTP/1.1 "
    head_code_200 = "200 "
    head_status_OK = "OK"

    head_content_length = "Content-Length: "
    head_content_type = "Content-Type: "
    content_type_html = "text/html"

    blank_line = ""



    import socket
    import threading

    class SocketHandler:

    def __init__(self, sock):
    self.sock = sock
    # 放置Http请求的头部信息
    self.headInfo = set()

    def startHandler(self):
    '''
    处理传入请求做两件事情
    1. 解析http协议
    2. 返回n内容
    :return:
    '''
    self.headHandler()
    self.sendRsp()
    return None

    def headHandler(self):
    # 两个下划线开头的变量是啥意思捏?
    self.headInfo = self.__getAllLine()
    print(self.headInfo)
    return None

    def sendRsp(self):
    data = "HELLO WORLD"
    self.__sendRspAll(data)
    return None

    #####################################

    def __getLine(self):

    b1 = self.sock.recv(1)
    b2 = 0
    data = b''

    while b2 != b' ' and b1 != b' ' :
    b2 = b1
    b1 = self.sock.recv(1)

    data += bytes(b2)

    return data.strip(b' ')


    def __getAllLine(self):

    data = b''
    dataList = list()
    data = b''

    while True:
    data = self.__getLine()
    if data:
    dataList.append(data)
    else:
    return dataList

    return None

    def __sendRspLine(self,data):

    data += " "
    self.sock.send(data.encode("ASCII"))
    return None


    def __sendRspAll(self, data):


    self.__sendRspLine("HTTP/1.1 200 OK")

    strRsp = "Content-Length: "
    strRsp += str(len(data))
    self.__sendRspLine( strRsp )

    self.__sendRspLine("Content-Type: text/html")

    self.__sendRspLine("")
    self.__sendRspLine(data)


    class WebServer():


    def __init__(self, ip=ServerContent.ip, port=ServerContent.port):
    self.ip = ip
    self.port = port

    self.sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
    self.sock.bind((self.ip, self.port))
    self.sock.listen(1)
    print("WebServer is started............................")

    def start(self):
    '''
    服务器程序一共永久性不间断提供服务
    :return:
    '''
    while True:
    skt, addr = self.sock.accept()

    if skt:
    print("Received a socket {0} from {1} ................. ".format(skt.getpeername(), addr))
    # sockHandler负责具体通信
    sockHandler = SocketHandler(skt)
    thr = threading.Thread(target=sockHandler.startHandler , args=( ) )
    thr.setDaemon(True)
    thr.start()
    thr.join()

    skt.close()
    print("Socket {0} handling is done............".format(addr))



    if __name__ == '__main__':
    ws = WebServer()
    ws.start()

    v06-返回静态页面-返回html页面
    class ServerContent:
    ip = '127.0.0.1'
    port = 9999

    head_protocal = "HTTP/1.1 "
    head_code_200 = "200 "
    head_status_OK = "OK"

    head_content_length = "Content-Length: "
    head_content_type = "Content-Type: "
    content_type_html = "text/html"

    blank_line = ""



    import socket
    import threading

    class SocketHandler:

    def __init__(self, sock):
    self.sock = sock
    # 放置Http请求的头部信息
    self.headInfo = set()

    def startHandler(self):
    '''
    处理传入请求做两件事情
    1. 解析http协议
    2. 返回n内容
    :return:
    '''
    self.headHandler()
    self.sendRsp()
    return None

    def headHandler(self):
    # 两个下划线开头的变量是啥意思捏?
    self.headInfo = self.__getAllLine()
    print(self.headInfo)
    return None


    def sendRsp(self):
    data = "HELLO WORLD"
    '''
    想返回一个静态页面,可以考虑把静态页面文件读入,作为str类型
    然后作为一共长字符串返回
    '''

    fp = r'.webapphello.html'

    with open(fp, mode='r', encoding='utf-8') as f:
    data = f.read()
    self.__sendRspAll(data)

    return None

    #####################################

    def __getLine(self):

    b1 = self.sock.recv(1)
    b2 = 0
    data = b''

    while b2 != b' ' and b1 != b' ' :
    b2 = b1
    b1 = self.sock.recv(1)

    data += bytes(b2)

    return data.strip(b' ')


    def __getAllLine(self):

    data = b''
    dataList = list()
    data = b''

    while True:
    data = self.__getLine()
    if data:
    dataList.append(data)
    else:
    return dataList

    return None

    def __sendRspLine(self,data):

    data += " "
    self.sock.send(data.encode())
    return None


    def __sendRspAll(self, data):


    self.__sendRspLine("HTTP/1.1 200 OK")

    strRsp = "Content-Length: "
    strRsp += str(len(data))
    self.__sendRspLine( strRsp )

    self.__sendRspLine("Content-Type: text/html")

    self.__sendRspLine("")
    self.__sendRspLine(data)


    class WebServer():


    def __init__(self, ip=ServerContent.ip, port=ServerContent.port):
    self.ip = ip
    self.port = port

    self.sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
    self.sock.bind((self.ip, self.port))
    self.sock.listen(1)
    print("WebServer is started............................")

    def start(self):
    '''
    服务器程序一共永久性不间断提供服务
    :return:
    '''
    while True:
    skt, addr = self.sock.accept()

    if skt:
    print("Received a socket {0} from {1} ................. ".format(skt.getpeername(), addr))
    # sockHandler负责具体通信
    sockHandler = SocketHandler(skt)
    thr = threading.Thread(target=sockHandler.startHandler , args=( ) )
    thr.setDaemon(True)
    thr.start()
    thr.join()

    skt.close()
    print("Socket {0} handling is done............".format(addr))



    if __name__ == '__main__':
    ws = WebServer()
    ws.start()

    webapp:hello.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>北京图灵学院欢迎您</title>
    </head>
    <body>

    <h1 style="color:blue"> 我爱北京图灵学院刘大拿</h1>

    </body>
    </html>

    v07-添加路由:
    class ServerContent:
    ip = '127.0.0.1'
    port = 9999

    head_protocal = "HTTP/1.1 "
    head_code_200 = "200 "
    head_status_OK = "OK"

    head_content_length = "Content-Length: "
    head_content_type = "Content-Type: "
    content_type_html = "text/html"

    blank_line = ""



    import socket
    import threading

    class SocketHandler:

    def __init__(self, sock):
    self.sock = sock
    # 放置Http请求的头部信息
    self.headInfo = dict()

    def startHandler(self):
    '''
    处理传入请求做两件事情
    1. 解析http协议
    2. 返回n内容
    :return:
    '''
    self.headHandler()
    self.reqRoute()
    return None

    def reqRoute(self):

    uri = self.headInfo.get("uri")
    if uri == b"/":
    self.sendRsp(r"./webapp/hello.html")
    return None
    if uri == b"/favicon.ico":
    self.sendStaticIco(r"./static/fav.jfif")
    return None

    self.sendRsp(r"./webapp/404.html")

    def sendStaticIco(self, fp):
    with open(fp, mode='rb') as f:
    ico = f.read()
    self.__sendRspAll(ico)

    def headHandler(self):
    self.headInfo = dict()
    tmpHead = self.__getAllLine()
    for line in tmpHead:
    if b":" in line:
    # split的具体含义
    infos = line.split(b": ")
    self.headInfo[infos[0]] = infos[1]
    else:
    infos = line.split(b" ")
    self.headInfo["protocal"] = infos[2]
    self.headInfo["method"] = infos[0]
    self.headInfo["uri"] = infos[1]


    def sendRsp(self, fp):
    data = "HELLO WORLD"
    '''
    想返回一个静态页面,可以考虑把静态页面文件读入,作为str类型
    然后作为一共长字符串返回
    '''

    #r'.webapphello.html'

    with open(fp, mode='r', encoding='utf-8') as f:
    data = f.read()
    self.__sendRspAll(data)

    return None

    #####################################

    def __getLine(self):

    b1 = self.sock.recv(1)
    b2 = 0
    data = b''

    while b2 != b' ' and b1 != b' ' :
    b2 = b1
    b1 = self.sock.recv(1)

    data += bytes(b2)

    return data.strip(b' ')


    def __getAllLine(self):

    data = b''
    dataList = list()
    data = b''

    while True:
    data = self.__getLine()
    if data:
    dataList.append(data)
    else:
    return dataList

    return None

    def __sendRspLine(self,data):

    if type(data) == bytes:
    self.sock.send(data)
    else:
    data += " "
    self.sock.send(data.encode())
    return None


    def __sendRspAll(self, data):


    self.__sendRspLine("HTTP/1.1 200 OK")

    strRsp = "Content-Length: "
    strRsp += str(len(data))
    self.__sendRspLine( strRsp )

    self.__sendRspLine("Content-Type: text/html")

    self.__sendRspLine("")
    self.__sendRspLine(data)


    class WebServer():


    def __init__(self, ip=ServerContent.ip, port=ServerContent.port):
    self.ip = ip
    self.port = port

    self.sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
    self.sock.bind((self.ip, self.port))
    self.sock.listen(1)
    print("WebServer is started............................")

    def start(self):
    '''
    服务器程序一共永久性不间断提供服务
    :return:
    '''
    while True:
    skt, addr = self.sock.accept()

    if skt:
    print("Received a socket {0} from {1} ................. ".format(skt.getpeername(), addr))
    # sockHandler负责具体通信
    sockHandler = SocketHandler(skt)
    thr = threading.Thread(target=sockHandler.startHandler , args=( ) )
    thr.setDaemon(True)
    thr.start()
    thr.join()

    skt.close()
    print("Socket {0} handling is done............".format(addr))



    if __name__ == '__main__':
    ws = WebServer()
    ws.start()
     
     
     
     
     
     

    <wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">





  • 相关阅读:
    使用Python创建TCP代理之工业时代造轮子
    CVE-2020-0796 SMB远程代码执行漏洞(分析、验证及加固)
    Oracle 找到引起账户锁定的IP
    【OGG 故障处理】OGG-01031
    【OGG 故障处理】OGG-01028
    【OGG 故障处理】 丢失归档恢复
    19C imp 导入合并表空间
    CentOS 7 配置VNCServer
    ORA-3136 问题处理
    HugePages概述--翻译自19C文档
  • 原文地址:https://www.cnblogs.com/xuxaut-558/p/10048003.html
Copyright © 2011-2022 走看看