1. 一些协议的相关概念
协议是网络协议的简称;
网络协议是通信计算机双方必须共同遵从的一组约定。
如怎么样建立连接,怎么样互相识别等。
只有遵守这个约定,计算机之间才能互相通信交流
协议三要素:
语法、语义、时序
协议族/簇/组:
协议族/簇/组:多个相关协议的组合
常见的传输层协议有:TCP、UDP
2. socket
Socket是一种网络通信协议,它提供了一种在网络上进行数据传输的方式。
Socket可以在不同的计算机之间建立连接,使得它们之间可以互相传输数据。
Socket通常用于编写网络应用程序,如聊天室、在线游戏、文件传输等。
Socket通信是基于客户端-服务器模型的,其中客户端向服务器发送请求,服务器接收请求并响应客户端。
Socket通信使用TCP或UDP协议进行数据传输。
TCP协议提供了可靠的数据传输,确保数据的正确性和完整性,但是传输速度较慢;
而UDP协议则提供了快速的数据传输,但是不保证数据的正确性和完整性。
网络三要素:
IP,PORT,协议
本地socket实例:
在所有语言中,都有封装好的socket方法,我们在进行网络编程时,可以直接调用
下面是一个python的socket实例:
由于是在本地进行C/S(serve/client,即服务端向客户端)效果演示,需要新建2个py文件
先新建一个服务端 server.py文件,由于目前还没有程序来进行访问,执行后会一直卡着,如下:
import socket
sock = socket.socket()
sock.bind(("xxx.xx.xx.x",8890)) #输入ip和端口号
sock.listen(5)
#等待客户端链接
print("server is waiting……")
conn,addr = sock.accept() #等待客户端来链接
print("conn",conn)
print("addr",addr)
conn.send(b"HTTP/1.1 200 ok\r\n\r\nhello world!") #发送符合http格式的字符串信息
data = conn.recv(1024) #接收符合格式的客户端内容,最大1024
print("data:",data)
#输出:由于还没有客户端发起访问,所以一直显示:
server is waiting……
再新建一个客户端client.py文件,先执行上面的py文件
再执行如下的py文件,第二个py文件执行完不会有任何输出
import socket
sock = socket.socket()
sock.connect(("xxx.xx.xx.x.x",端口号)) #这里的ip和端口号需要与服务端一致
#向服务端发送一条消息:
sock.send(b"hello world!")
再看第一个py文件的控制台,会显示已链接成功及链接信息、接收到的客户端信息:
data返回:hello world!
同样,服务端启动后,也可以向客户端发送消息
本地模拟socket--b/s程序:
b/s(Browser/Server):指的浏览器和服务器架构模式
在这种架构下,客户端通过WWW浏览器来实现与服务器的链接
浏览器发起访问请求后,服务端返回对应的数据
如下,简单模拟一个京东服务器的实例:
#本地模拟写一个京东服务器:
import socket
sock = socket.socket()
sock.bind(("xxx.xx.xx.x.x",8890))
sock.listen(3)
print("京东服务器已启动……")
while 1:
conn,addr = sock.accept() #等待客户端来链接
print("data:",data)
conn.send(b"HTTP/1.1 200 ok\r\n\r\nhello world!") #发送符合http协议格式的字符串消息
data = conn.recv(1024) #接收符合格式的客户端内容,最大1024
conn.close()
#运行后输出:
京东服务器已启动……
打开浏览器 -> 直接输入上述代码中的ip:端口号,浏览器端接收显示信息如下:
通信协议的固定格式:conn.send(b"HTTP/1.1 200 ok\r\n\r\nxxx……xx")
如果发送的内容,没有按照http的固定格式写,会发生什么情况呢?
#本地模拟写一个京东服务器:
import socket
sock = socket.socket()
sock.bind(("xxx.xx.xx.x.x",8890))
sock.listen(3)
print("京东服务器已启动……")
while 1:
conn,addr = sock.accept() #等待客户端来链接
print("data:",data)
conn.send(b"hello world!") #发送不符合http协议格式的字符串消息,可以发送成功
data = conn.recv(1024)
conn.close()
#运行后输出:
京东服务器已启动……
重新打开浏览器 -> 直接输入上述代码中的ip:端口号,浏览器端接收显示信息如下:
这时候,服务端启动成功 -> 浏览器也拿到了服务返回的数据,但是由于它无法解析内容
所以如上截图,无法正常显示。
主要原因是,代码中没有遵循http协议的传输规则,导致服务端无法解析。
虽然作为爬虫来讲,我们不需要知道如何进行具体开发,但是我们需要知其所以然,
所以接下来,我们需要了解http网络协议的相关知识。
3. http网络协议
http协议简介:
http协议是超文本传输控制协议。
是一种按照URL指示,将超文本文档从一台主机(web服务器)传输到另一台主机(浏览器)的应用层协议,以实现超链接的功能。
http协议的特性:
http协议具有以下4个特性:
(1) 基于TCP/IP协议
http协议是基于TCP/IP协议之上的应用层协议。
(2) 基于请求响应模式
BTTP协议规定,请求从客户端发出,最后服务器端响应该请求并返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有接收到请求之前不会发送响应。
(3)无状态保存
HTP是一种不保存状态,即无状态(stateless)协议。HTTP协议自身不对请求和响应之间的通信状态进行保存。
也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化理。
使用BTTP协议,每当有新的请求发送时,就会有对应的新响应产生。协议本身并不保留之前一切的请求或响应报文的信息。
这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成如此简单。
(4)短连接和长连接
HTTP1.0默认使用的是短连接。浏览器和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。HTTP/1.1起,默认使用长连接。要使用长连接,客户端和服务器HTTP首部的Connection都要设置为keep-alive,才能支持长连接HTTP长连接,指的是复用TCP连接。
多个HTTP请求可以复用同一个TCP连接,这就节省了TCP连接建立和断开的消耗。
4. http协议--请求报文
htp协议包含:由浏览器发送数据到服务器需要遵循的请求协议、服务器发送数据到浏览器需要遵循的请求协议。用于HTTP协议交互的信被为HTTP报文。
请求端(客户端)的HTTP报文 做请求报文,响应端(服务器端)的 做响应报文。
HTTP报文本身是由多行数据构成的字文本。
一个完整的URL包括:协议、ip、端口、路径、参数
例如:https://www.baidu.com/s?wd=yuan
其中https是协议
www.baidu.com 是IP
端口默认80
/s是路径
参数是wd=yuan
请求报文方式汇总:
方法(操作) | 含义 | 方法(操作) | 含义 |
GET | 请求读取一个web页面 | HEAD | 请求读取一个web页面的首部 |
POST | 附加一个命名资源(如web页面) | PUT | 请求存储一个web页面 |
DELETE | 删除web页面 | TRACE | 用于测试,要求服务器送回收到的请求 |
CONNECT | 用于代理服务器 | OPTION | 查询特定选项 |
常见--get请求&post请求:
● GET请求:
get提交的数据只会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456.
● POST请求:
post方法是把提交的数据放在HTTP包的请求体中。
格式如下:
请求首行
若干个请求头每个占一行 空一行
请求体数据
GET提交的数据大小有限制(因为浏览器对URL的长度有限制)
而POST方法提交的数据没有限制
首部字段/消息头含义
头(header) | 类型 | 说明 |
User-Agent | 请求 | 关于浏览器和它平台的信息,如Mozilla5.0 |
Accept | 请求 | 客户能处理的页面的类型,如text/html |
Accept-Charst | 请求 | 客户可以接受的字符集,如Unicode-1-1 |
Accept-Encoding | 请求 | 客户能处理的页面编码方法,如gzip |
Host | 请求 | 可能处理的DNS名称。从URL中提取出来,必需 |
Authorization | 请求 | 客户的信息凭据列表 |
Cookie | 请求 | 将以前设置的Cookie送回服务器,可用来作为会话信息 |
Date | 双向 | 消息被发送时的日期和时间 |
Server | 响应 | 关于服务器的信息,如Microsoft-lls/6.0 |
Content-Ecoding | 响应 | 内容是如何被编码的(如gzip) |
Content-Language | 响应 | 页面所使用的自然语言 |
Content-Length | 响应 | 以字节计算的页面长度 |
Content-Type | 响应 | 页面的MIME类型(组装类型:x-mm-form表单、josn) |
Last-Modified | 响应 | 页面最后被修改的时间和日期,在页面缓存机制中意义重大 |
Location | 响应 | 指示客户请求发送给别处,即重定向到另一个URL |
Set-Cookie | 响应 | 服务器希望客户报错一个Cookie |
http请求示例
例如:请求 www.baidu.com
打开浏览器 -> 快捷键F12,或者右键检查--network
请求 www.baidu.com时的--请求头文件:
基于postman完成请求测试
基于前面的socket代码,首先运行代码
ps:如果连续多次运行代码报错,就修改端口号
import socket
sock = socket.socket()
sock.bind(("xxx.xx.xx.x.x",8890)) #本地ip,端口号(可随意写4位数)
sock.listen(3)
print("京东服务器已启动……")
while 1:
conn,addr = sock.accept() #等待客户端链接
print("data:",data)
conn.send(b"hello back girl!") #要发送的字符串消息
data = conn.recv(1024) #接收客服端的消息,最大长度1024
conn.close()
将代码中的ip:端口号,直接输入到postman
- >如果是post请求:需要Body中填写key、value
- >如果是get请求:填写Params中填写key、value
如下截图为psot:
然后点击send:Body中就会显示接收到的信息(代码中的send)
postman--点击send时,将上述截图的2个键值对,作为请求体传给服务器
以下是pycharm控制台输出中接收的请求信息,复制出来如下
可以看出是与正常浏览器进行访问时的请求内容相同:
POSTTP/.1
User-Agent: PostmanRuntime/7.29.2
Accept:*/*
Postman-Token: 07e336c1-5bc4-4759-b3db-fleeec0604d8
inHost:27.0.0.1:889
Accep-Encoding: gzip, deflate, brrinom
ection: keep-aliverlo
content-Type: application/x-mm-form-urlencodedrino
tent-Length:20\r\n\r\nuser=yuan&pwd=123456
postman中接收到服务器发送的信息
服务器中也接收到了postman发送请求的内容
至此,说明测试成功~
★组装格式tips:
以上述栗子,请求中的体中的key、value的组装格式通常有如下两种:
x-mm-formurlencodedrino(表单格式):user = yua&pwd=123456
josn格式:{"user":"yuan","pwd":"123456"}
进行请求的时候,上面任意一种组装格式都没问题
but:在请求头_content-Type中必须声明组装格式,不然服务器拿到的只是一个字符串,无法进行解析。
5. http响应格式
响应示例:
对上面的socket代码进行加工:
添加请求头信息:Content-Type:text/htm
让"hello world"变成一级标题:"hello world"放在<h1> </h1>中间
并且添加一张图片:百度找一张图片 -> 点击图片右键 -> 复制图片地址,进行添加
代码如下:
sock = socket.socket()
sock.bind(("xxx.xxx.x.xxx",8890))
sock.listen(3)
print("京东服务器已启动……")
while 1:
conn,addr = sock.accept()
data = conn.recv(1024)
print("data:",data)
conn.send ( b"HTTP/1.1 200 ok\r\ncontent-type:text/html\r\n\r\n<h1>hello world!</h1><img "
b"src='https://img2.baidu.com/it/u=3413024138,1887722785&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500'>") #发送符合格式的字符串消息+消息设为一级标题+一张图片
conn.close()
再次打开浏览器,输入ip:端口号
就显示出来了粗标题的"hello world",以及一张图片:
开发者工具中,显示表头(响应头)的类型为代码中指定的text/htm类型:
text/htm表示发送请求后,传到服务端,需要进行前端渲染,即显示出我们想要的样式
如果Content-Type,写为text/plain,即不会进行任何渲染,展示为纯字节文本
响应状态码:
状态码的职责是当客户端向服务器端发送请求时, 返回的请求结果。
借助状态码,用户可以知道服务器端是正常理了请求,还是出现了问题 。
状态码如200 OK,以3位数字和原因组成。
>>状态码的含义,可参考W3C的HTTP1.1标准规范-RFC2616:
状态码分类汇总
状态码 | 含义 | 例子 |
1XX | 通知信息 | 100=服务器正在处理客户请求 |
2XX | 成功 | 200=请求成功(ok) |
3XX | 重定向 | 301=页面改变了位置 |
4XX | 客户错误 | 403=静止的页面;404=页面未找到 |
5XX | 服务器错误 | 500=服务器内部错误;503=以后再试 |