1.http认识
-
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是互联网上应用最为广泛的一种网络协议,用于web服务器与浏览器之间传输超文本数据的协议
-
HTTP是一个基于TCP/IP通信协议来传递数据(HTML网页文件, 图片文件,视频文件, 查询结果等等)
html:(Hyper Text Mark-up Language)超文本标记语言,用html来编写网页
-
通俗的讲: HTTP是在网络上传输HTML网页的协议,用于浏览器和服务器的通信。
2. HTTP 协议的 Request/Response(请求/响应)模型
3. HTTP 请求报文格式分析
下面就是我们要请求的示例数据:
GET /index.html HTTP/1.1 Host: 192.168.192.221:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: BAIDUID=8FD6ED496A03231D920484C6379517CF:FG=1;
1.GET / HTTP/1.1 叫做请求行. 里面包含3个信息, 以空格隔开
2.请求头. 除了第一行之外, 剩下的所有数据的格式都是类似的.叫请求头。
请求报文格式总结
4. HTTP 响应报文格式分析
HTTP/1.1 200 OK Connection: Keep-Alive Content-Encoding: gzip Content-Type: text/html; charset=utf-8 Date: Wed, 14 Mar 2018 09:52:48 GMT Server: BWS/1.1
响应数据格式总结
浏览器访问网站的过程
基本流程如下:
- 用户输入网址.
- 浏览器请求DNS服务器, 获取域名对应的IP地址.
- 请求连接该IP地址服务器.
- 发送资源请求. (HTTP协议)
- web服务器接收到请求, 并解析请求, 判断用户意图.
- 获取用户想要的资源.
- 将资源返回给http服务器程序.
- http服务器程序将资源数据通过网络发送给浏览器.
- 浏览器解析呈现请求的数据.
TCP通信的整个过程,如下图:
1. TCP短连接
模拟一种TCP短连接的情况:
- client 向 server 发起连接请求
- server 接到请求,双方建立连接
- client 向 server 发送消息
- server 回应 client
- 一次读写完成,此时双方任何一个都可以发起 close 操作
在步骤5中,一般都是 client 先发起 close 操作。当然也不排除有特殊的情况。
从上面的描述看,短连接一般只会在 client/server 间传递一次读写操作!
2. TCP长连接
再模拟一种长连接的情况:
- client 向 server 发起连接
- server 接到请求,双方建立连接
- client 向 server 发送消息
- server 回应 client
- 一次读写完成,连接不关闭
- 后续读写操作...
- 长时间操作之后client发起关闭请求
3. TCP/IP协议(族)
互联网协议包含了上百种协议标准,但是最重要的两个协议是TCP和IP协议,所以,大家把互联网的协议简称TCP/IP协议(族)
常用的网络协议如下图所示:
- 网络接口层(物理层、数据链路层):包括传输介质(网线)、计算机中对应的网络接口卡等,其实这一层tcp/ip协议是没有定义的,给其上层"网络层"提供访问接口.
- 网络层(互联网层):主要用IP地址来完成对主机的寻址,它还负责数据包在多种网络中的路由
- 运输层:主要为两台主机上的应用提供端到端的通信.
- 应用层:为用户提供所需的服务,比如http服务,ftp服务,smtp服务等.
1. 模拟浏览器访问服务端
import socket def main(): # 1.创建tcp客户端socket对象 http_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2. 连接服务端 http_client_socket.connect(('127.0.0.1', 7788)) # 3. 发送http请求报文格式 """ 1. 请求行 : GET /index.html HTTP/1.1 2. 请求头 : HOST:127.0.0.1:7788 3. 分隔符 ‘\r\n’ 4. 请求体 product_id=1001 """ request_line = 'GET /index.html HTTP/1.1\r\n' # 请求行,必须有 request_headers = 'HOST: 127.0.0.1:7788\r\n' # 请求头 request_headers += 'Accept: text/html\r\n' split = "\r\n" # 请求头与请求体分隔符 request_body = "product_id=1001\r\n" request_data = request_line + request_headers + split + request_body # 拼接请求报文数据 # 发送请求数据到服务端,发送前需编码 http_client_socket.send(request_data.encode("utf-8")) # 等待接受从服务端应答的消息 response_data = http_client_socket.recv(1024) print("http服务端应答的数据:", response_data.decode()) # 解码输出 # 关闭套接字 http_client_socket.close() if __name__ == '__main__': main()
2. 简单HTTP服务器实现
1 import socket 2 3 4 def handle_client(client_socket): 5 """处理浏览器客户端的请求""" 6 7 # 等待接收客户端发送的消息 8 recv_data = client_socket.recv(4096) 9 10 # 解码数据 11 request_data = recv_data.decode("utf-8") 12 13 # 显示接收到的请求报文数据 14 print(request_data) 15 16 # 按照http 响应报文格式去回复客户端 17 """http 响应报文格式 18 1. 响应行 : HTTP/1.1 200 OK 19 2. 响应头 Server: mimiweb1.0 Connection: Keep-alive 20 3. 分隔符 \r\n 21 4. 响应体 very good 22 """ 23 response_line = "HTTP/1.1 200 OK\r\n" # 响应行,必须有 24 response_headers = "Server: mimiweb1.0\r\n" 25 response_headers += "Connection: Keep-alive\r\n" 26 split = "\r\n" # 请求头与请求体的分隔符 27 response_body = "very good\r\n" 28 29 # 拼接响应报文数据 30 response_datas = response_line + response_headers + split + response_body 31 32 # 向客户端发送响应报文数据 33 client_socket.send(response_datas.encode("utf-8")) 34 35 # 关闭套接字 36 client_socket.close() 37 38 39 def main(): 40 """程序主控制入口""" 41 42 # 创建监听套接字 43 http_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 44 45 # 当套接字四次挥手,可立即复用地址端口 46 http_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) 47 48 # 服务端绑定端口 49 http_server_socket.bind(('', 7788)) 50 51 # 开启监听 52 http_server_socket.listen(128) 53 54 # 等待接受浏览器客户端的请求 55 while True: 56 client_socket, client_addr = http_server_socket.accept() 57 print("有新的客户端请求,来自>>>", client_addr) 58 59 # 在函数中为客户端提供服务 60 handle_client(client_socket) 61 62 63 if __name__ == '__main__': 64 main()
服务器端
客户端