Webserver-HTTP项目(深入理解HTTP协议)

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

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

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

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

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

# v04-面向对象重构- 两个对象:    - 一个负责监听接受传入socket, WebServer    - 一个负责通讯, 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("正在监听......")

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

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

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

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

skt.close()sock.close()

解析传入HTTP:

import socket

def getHttpHeader(skt):‘‘‘得到传入socket的http请求头: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‘\r‘, b‘\n‘, b表示是一个bytes格式    ‘‘‘# 每次从socket读取一个byte内容b1 = skt.recv(1)b2 = 0#data用来存放读取的行的内容data = b‘‘

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

data += bytes(b2)

# decode 需要一个参数,即编码,但是不给的话就采用默认utf-8解码return data.strip(b‘\r‘).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("正在监听......")

# 接受一个传进来的socketprint("准备接受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):‘‘‘得到传入socket的http请求头: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‘\r‘, b‘\n‘, b表示是一个bytes格式    ‘‘‘# 每次从socket读取一个byte内容b1 = skt.recv(1)b2 = 0#data用来存放读取的行的内容data = b‘‘

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

data += bytes(b2)

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

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

# 构建返回头rsp_1 = "HTTP/1.1 200 OK\r\n"rsp_2 = "Date: 20180616\r\n"# 求返回内容的长度len_value= len(content)rsp_3 = "Content-Length: {0}\r\n".format(len_value)rsp_4 = "\r\n"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("正在监听......")

# 接受一个传进来的socketprint("准备接受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 socketimport 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 = 0data = b‘‘

while  b2 != b‘\r‘ and b1 != b‘\n‘ :b2 = b1            b1 = self.sock.recv(1)

data += bytes(b2)

return data.strip(b‘\r‘)

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 += "\r\n"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 = ipself.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 socketimport 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 = 0data = b‘‘

while  b2 != b‘\r‘ and b1 != b‘\n‘ :b2 = b1            b1 = self.sock.recv(1)

data += bytes(b2)

return data.strip(b‘\r‘)

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 += "\r\n"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 = ipself.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 socketimport 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‘.\webapp\hello.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 = 0data = b‘‘

while  b2 != b‘\r‘ and b1 != b‘\n‘ :b2 = b1            b1 = self.sock.recv(1)

data += bytes(b2)

return data.strip(b‘\r‘)

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 += "\r\n"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 = ipself.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 socketimport 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 Noneif 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‘.\webapp\hello.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 = 0data = b‘‘

while  b2 != b‘\r‘ and b1 != b‘\n‘ :b2 = b1            b1 = self.sock.recv(1)

data += bytes(b2)

return data.strip(b‘\r‘)

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 += "\r\n"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 = ipself.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;">

来自为知笔记(Wiz)

原文地址:https://www.cnblogs.com/xuxaut-558/p/10048003.html

时间: 2024-08-03 17:27:28

Webserver-HTTP项目(深入理解HTTP协议)的相关文章

深入理解HTTP协议、HTTP协议原理分析

深入理解HTTP协议.HTTP协议原理分析 目录(?)[+] http协议学习系列 1. 基础概念篇 1.1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本.其中最著名的就是RFC 26

深入理解HTTP协议(转)原出处已不明

http协议学习系列---我从这里转来的http://www.blogjava.net/zjusuyong/articles/304788.html 1. 基础概念篇 1.1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC

转载和积累系列 - 深入理解HTTP协议

深入理解HTTP协议 1. 基础概念篇 1.1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本.其中最著名的就是RFC 2616.RFC 2616定义了今天普遍使用的一个版本——HTTP

(转存 作者未知)深入理解HTML协议

深入理解HTML协议 http协议学 习系列 1. 基础概念篇 1.1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系 列的RFC,RFC 1945定义了HTTP/1.0版本.其中最著名的就是RFC 2616.RFC 2616定义了今天普遍

转战物联网&#183;基础篇05-通俗理解MQTT协议的实现原理和异步方式

??网络上搜索MQTT协议,会出现太多的解释,这里就不做官方标准释义的复制了.这一节我们从实战理解角度,通俗的将MQTT协议的作用及实现原理说一下,旨在可以快速理解MQTT协议.所以可能会出现很多看似不标准的解释,但是更容易理解MQTT的内涵,对MQTT十分精通者请忽略此文. ??在物联网项目中,经常出现的要求是"有限环境".什么意思呢,通俗说就是网络可能不太稳定,带宽也可能很小,网速也比较低,硬件MCU性能也很低,要求在这种情况下也能可靠联网传输信息.看到这里大家就会想到我前面提到的

【报文】理解HTTP协议的Request/Response(请求响应)模型

[报文]理解HTTP协议的Request/Response(请求响应)模型 系列目录 [简介]"请求/响应"模型 http://www.cnblogs.com/engraver-lxw/p/7550514.html [原理]理解HTTP协议的Request/Response(请求响应)模型 http://www.cnblogs.com/engraver-lxw/p/7550691.html [报文]理解HTTP协议的Request/Response(请求响应)模型--当前 http:/

对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(4)

chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angularjs文章:http://chsakell.com/2015/08/23/building-single-page-applications-using-web-api-and-angularjs-free-e-book/ 这里记录下对此项目的理解.分为如下几篇: ● 对一个前端使用AngularJ

对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(3)

chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angularjs文章:http://chsakell.com/2015/08/23/building-single-page-applications-using-web-api-and-angularjs-free-e-book/ 这里记录下对此项目的理解.分为如下几篇: ● 对一个前端使用AngularJ

对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(1)

chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angularjs文章:http://chsakell.com/2015/08/23/building-single-page-applications-using-web-api-and-angularjs-free-e-book/ 这里记录下对此项目的理解.分为如下几篇: ● 对一个前端使用AngularJ