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;">





  • 相关阅读:
    vue-fullcalendar插件
    iframe 父框架调用子框架的函数
    关于调试的一点感想
    hdfs 删除和新增节点
    hadoop yarn 实战错误汇总
    Ganglia 安装 No package 'ck' found
    storm on yarn(CDH5) 部署笔记
    spark on yarn 安装笔记
    storm on yarn安装时 提交到yarn失败 failed
    yarn storm spark
  • 原文地址:https://www.cnblogs.com/xuxaut-558/p/10048003.html
Copyright © 2011-2022 走看看