在网络中唯一标识一台主机 ,这是一个逻辑地址;(IPV4 / IPV6)
目前主要使用的是IPV4,IPV6不能向前兼容IPV4,所以没得到广泛使用
在网络中的每条数据中都会包含两条信息:源端IP地址,目的端IP地址
PORT端口 :在一台主机上唯一标识一个进程 (范围:0~65535)
网络协议 :通信双方数据格式的约定,在通信领域,他是为了保障通信能够按照既定流程进行,而给参与各方的一套标准;
协议分层 :
协议的封装,在整个通信环境中使用起来更加方便
协议栈: 由框架和协议共同构成协议栈,如OSI、TCP/IP;
尽管TCP/IP协议栈及其对应的分层模型在实际应用中大行其道,但人们在谈论技术的时候最频繁引用的就是OSI模型,它的最大贡献就是将协议、接口、服务进行相互独立;
(说白了就是实际用的少,分层太啰嗦,但是学术理论性较强,值得学习⭐)
OSI模型最大的特点就是将协议、服务和接口进行相互独立;
上面说到,OSI并没有得到广泛运用,这里总结如下:
两者联系:网络模型的作用都是为了规范通信流程;
这两个模型的根本区别就在于建立标准的方式,也就是上面谈到的OSI是先定义于OSI模型各层对应协议的定义,也就是说OSI模型是在缺乏对各层协议的充分了解下定义的,因此使用现有的协议和OSI模型来构建网络往往会出现无法满足服务规范的情况;
而TCP/IP协议相反,这个模型一开始就是对TCP协议和IP协议所作的描述,因此该模型定义的服务与TCP和IP协议高度吻合;而且TCP/IP协议栈中还有很多协议是先在一些设备上进行使用并实现了通信,然后再一边使用一边制定具体的协议规范;
可以看到,TCP/IP将OSI的应用层、表示层、会话层归纳到了应用层,这样做是合理的,然而将数据链路层和物理层归纳到一起是不行的,会造成一定的混淆,毕竟这两层在通信中扮演的角色截然不同 ,所以也出现了TCP/IP 5层模型,即是将网络接入层还是分开成数据链路层和物理层;
这里我将结合上面的TCP/IP模型和一些协议来讲解数据在一次通信中如何被处理的;
封装: 很少人愿意在直接在自己的包裹上写上收件人的名字、是否加急、是否在对方收到时给自己发送短信,所以需要在包裹上贴一张快递单;
同理呀!要传输的数据本身也不会附带一段信息来描述目的地、数据类型、是否加密、如何加密解密等,因此要传输数据,也必须在数据上添加相应的信息,至于添加甚麽样的信息、甚麽样的长度和格式等具体的标准,要由对通信进行标准化的协议来进行定义,而这正是协议兑现服务的方式;
然后传输设备根据协议向数据负载中添加功能性信息的操作称为封装;
注意上图:为了突出头部封装的过程,图中没有包含将一整段信息拆分成多个数据包的处理过程,也没有考虑协议给数据包封装尾部的情况;
综上,我们可以得出如下结论:
应用层知名协议:HTTP、FTP、DNS、DHCP
所谓协议,就是规定的意思,HTTP协议就是HTTP规定的意思,它定义了两台设备之间交互网页信息的流程;
HTTP协议是基于CS架构进行通信的
当TCP连接建立起来后,客户端只能向服务端发送一条HTTP请求,当服务器用被请求的内容对该消息做出响应后,这条TCP连接就会断开,如果双方还需要通信,则需重新建立连接;
客户端和服务端建立一条TCP连接后,可以复用这条TCP连接发送多个请求-响应消息,甚至客户端可以在前一个请求尚未收到响应消息之前就能发送下一个请求消息;
注意:由于使用HTTP1.1协议进行通信的客户端和服务器并不知道这个为了传输消息而建立的持续TCP连接应该维持多久,因此HTTP1.1服务器需要设置一个时间间隔,指定一段时间没有接收到HTTP请求消息的连接应当断开;因为对于HTTP服务器而言,与一台客户端长期保持TCP连接却不传输消息会耗掉大量资源;
网址——URL(统一资源定位符):https://www.baidu.com (下面这个是一个完整的URL结构)
http://user:[email protected]:80/dir/index.html?uid=1#ch1
协议方案名称/用户名:密码@服务器地址:端口号/请求资源路径?查询字符串#片段标识符
查询字符串是用户提交给服务器的数据信息,这些提交的信息中若是出现特殊字符,则有可能与URL中的间隔符
协议分为请求和响应,对应的如下:
首行:
请求首行 (格式:请求方法 URL 协议版本)
请求方法:GET/POST(等等,不止这两种) 区别:GET没有正文,提交的数据在URL的查询字符中
协议版本:0.9/1.0/1.1/2 (可以去搜索各大版本的区别特性)
响应首行 (格式:协议版本 响应状态码 状态码描述信息)
响应状态码(五大类):例如:1** / 2** / 3** / 4** / 5**
1** :通常是一些描述信息,服务器收到请求,需要请求者继续执行操作
2** :正确处理了你所请求的信息,已经OK了,常见的有 200
3** :重定向 (已经接收到你的信息,但让你转接到另外一个地址,这个地址在Location中)
4** :常见的有404,即请求资源不存在
5** :返回的是服务端错误
状态码了解网站 :https://www.runoob.com/http/http-status-codes.html
头部 (对应请求头和响应头)(下列没标明的既存在于请求头也存在于响应头)
以一个个key:value组成的键值对,并且各个键值对以\n或\r分隔
(注意:每个HTTP报文不是包含下面所有,根据需求来)
常见请求头:
常见响应头:
常见通用头:
在这里,提一下Session和Cookie:
Cookie:在网站中,http请求是无状态的(⭐)。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
Session:session和cookie的作用有点类似,都是为了存储用户相关的信息。不同的是,cookie是存储在本地浏览器,而session存储在服务器 (⭐)。存储在服务器的数据会更加的安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些session信息还是绰绰有余的。
空行
\r\n -------用于间隔头部与正文
正文 (GET提交的请求没有正文)
在HTTP请求报文的首行的请求方法,有如下几种:
HTTP操作命令 | 解释 |
---|---|
GET | 读取页面,一般来说GET方法应该只用于数据的读取,而不应当用于会产生副作用的非幂等的操作中。它期望的应该是而且是安全的、幂等的。这里的安全是指。请求不会影响到资源的状态 |
HEAD | 读取页面头部,类似于GET,只不过返回的响应中没有具体的内容,用于获取报头 |
POST | 向服务器传输附加信息进行处理请求(例如提交表单或者上传文件);数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改 |
PUT | 写入页面 |
DELETE | 删除页面,用于请求服务器删除所请求的URL所标识的资源。DELETE请求后指定资源将会被删除,DELETE方法也是幂等的 |
CONNECT | 通过代理连接 |
TRACE | 将客户端发送的请求发回,用于测试或诊断 |
OPTIONS | 请求可用选项的信息,即允许客户端查看服务器的性能 |
下面是我在我学校教务处系统的登陆界面抓取的一个http数据包(只截取了请求和响应部分,没截取正文。正文就是我那个登陆界面的源码):
GET http://59.74.168.16:8989/ HTTP/1.1
Host: 59.74.168.16:8989
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://jwc.xust.edu.cn/
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store
Date: Tue, 23 Jul 2019 03:33:54 GMT
Pragma: no-cache
Content-Length: 6610
Content-Type: text/html; charset=gb2312
Expires: -1
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Set-Cookie: yunsuo_session_verify=66b6530ff0a2386af2c269b0e7619959; expires=Fri, 26-Jul-19 11:33:54 GMT; path=/; HttpOnly
X-AspNet-Version: 1.1.4322
P3P: CP=CAO PSA OUR
Set-Cookie: ASP.NET_SessionId=slgkn555unoeljqlcieidpae; path=/
可以看到,上面的一部分是我们的请求信息:第一行是请求首行,后面的都是请求头
Host对应的是我教务系统的主机地址、referer对应的是我上次是从哪个地址跳转过来的,Accept-Encoding对应的是浏览器端能接受的一些编码格式,其他就不一一叙述了
下面一部分就是响应信息:第一行是响应首行,后面对应的是一些响应头
注意:每个包根据需求对应都会有不同的头部信息(响应头和请求头)
额外问题:
POST方法会产生两个TCP数据包?
答案:有的人实践得到,POST方法将头部信息和请求体分开发送,其实不一定,HTTP协议中并没有这样规定,根据浏览器不同,结果不同;
GET用于获取信息,POST用于提交信息?
答案:它们都是HTTP请求的方式,那么当然,都可以用来请求获取信息,例如在POST的请求体中为空,即不提交任何内容,但服务器收到POST请求也会传回响应信息;
对于HTTPS具体的加密过程,这里提供一篇较为权威的博客链接:
https://www.cnblogs.com/jesse131/p/9080925.html
功能:负责端与端之间的数据传输;不关心数据是如何传输的;
主要协议: TCP/UDP ,传输层协议只在终端系统中工作,只负责将应用程序需要发送的数据转交到网络层,反之亦然;
端口 :
五元组 :在网络通信中,每一条数据都必须带有以下关键信息 :(用于标识网络中的一条通信)
全称为传输控制协议,负责为不同终端系统的应用进程之间提供面向连接的通信服务,是一种可靠的传输层协议;
在为应用进程之间建立通信之前,TCP协议需要首先建立传输数据所需的连接 。一但TCP连接建立成功,应用进程之间就可以借助这条TCP连接相互发送上层数据了。此外,TCP协议能够对它所建立的TCP连接进行控制,包含下面几点:
当然,这些只是TCP为应用进程提供的一部分服务,要了解更多,可自行查阅TCP官方文档;
刚刚上面描述了,在TCP通信之间需要建立一条TCP连接;TCP连接建立完成后,终端之间就可以进行数据传输,注意在数据传输完成后,TCP会进行断开连接的过程(四次挥手)
所谓三次握手,先来看三次握手和四次挥手的总流程图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LUTLsRAD-1574557550144)(C:\Users\Laptop\AppData\Local\Temp\1563162227705.png)]
- 为什么握手是三次而不是两次
- 两次不安全,有可能SYN会延迟,缺乏状态保护的情况下,收到一个SYN就会建立一个新的socket,完整的状态保护避免对一个客户端创建多个socket ;有了三次握手,在收到第一个SYN后,此时服务端就等待客户端的ACK回复确认,这期间就算收到了客户端的新的SYN也不会理睬,就不会创建新的socket;
- 两次不安全,服务端无法通过客户端的SYN确定客户端具有数据收发能力,需要再次进行确认;
除了上面我总结的,在教科书里,是这样解释的(其实意思也差不多,这里给出来供大家衡量参考)
《计算机网络》第四版中讲“三次握手”的目的是**“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”** 书中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”。主要目的防止server端一直等待,浪费资源。
- 挥手为什么是四次
- 被动关闭方,收到FIN之后对其进行ACK回复,但是不能直接关闭socket,因为这时候用户有可能正在处理数据(socket接受缓冲区中有可能还有堆积的数据),需要用户来确认什么时候关闭socket发送FIN;因此ACK和FIN不能放在一起;
- 为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
- 这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
- 若是三次握手失败,服务端如何处理?
- 服务端超时等待之后,向客户端发送rst报文,然后释放新建的socket资源
SYN泛洪攻击-----------调研
主动关闭方TIME_WAIT状态的作用:
假设没有time_wait而是直接进入closed状态,释放socket资源造成的危害:
在主动关闭方发送的最后一次ACK丢失的情况下:如果客户端使用相同的地址信息立即重启,但是被动关闭方:
收到被动关闭方超时等待后重发的FIN包,对新连接赵成影响;
发送SYN请求,但是对方等待的是ACK,因为状态不对导致对新连接的影响
因此主动关闭方需要等待一段时间:若是对方重发FIN请求,可以对其再次进行确认回复
MSL:报文最大生命周期 (30秒)
等待两个MSL时间是为了让网络中延迟的报文都消失网络中不会对后续连接造成影响
大量time_wait解决方案:调整MSL时间,设置套接字选项(地址复用)
TCP的缺点:
TCP为了保证可靠传输,牺牲了部分性能,(有些性能的损失是没有必要的,比如ack丢失导致的重传)
TCP又采用了几种机制来避免无畏的性能损失以及提高性能的方法:
流量控制: 通过协议字段中的窗口大小(不会大于接收方的接收缓冲区中剩余空间的大小)字段控制发送方发送的数据大小;避免因为发送过快而接受方数据处理过慢导致接收缓冲区数据放满后,大量的数据丢失重传降低的性能;
窗口大小在每次对数据进行确认回复的时候都会进行重新协商;
每一条确认回复中的确认序号,都要保证之前的数据已经全部 完全收到,没有收到第一条回复,但是收到了第二条回复,认为第一条和第二条都已经正确传输,避免因为ack丢失而导致的数据重传。
快速重传机制: 接收方收到了第二条数据,但是没有收到第一条,则初步认为第一条数据丢失,则立即发送第一条数据的重传请求,并且连续发送三次(连续三次是避免因为网络阻塞、数据延迟到达而导致的重传)
拥塞控制:
网络通信开始时,并不会直接发送窗口大小的数据,而是以一种慢启动,快增长的形式进行数据传输,起到一个网络探测的作用,避免开始通信时因为网络不好导致的发送数据越多,丢失数据越多的重传性能损失,在快增长的过程中,若出现丢包则初始化拥塞窗口大小,重新开始探测网络状况;
接收方接收数据若是立即回复,则窗口大小会降低,会导致传输速度降低,因此接收方接收到数据之后,并不会立即回复,而会延迟一会(不超过500毫秒),在这期间,用户可又能将数据从接收缓冲区中取出,可以尽量大的能力保证窗口大小,保证传输速度不会降低;
每次接收方对发送的数据进行确认回复,若是单独发送一个数据报(仅仅包含一个tcp报头)是不划算的,解决方案就是将要进行的确认回复和将要发送的数据合到一起进行发送,就可省略一个tcp报头的发送,减少网络中不必要的流量信息;
定义: 数据不会直接发送,而是放到缓冲区中,操作系统选择一个合适的时机将合适大小的数据以字节流的形式发送出去,对方接收数据时可以一次性接收所有数据,也可以一次接受一点,分多次接受;
特性: 传输灵活,但是会造成粘包问题
粘包问题:
用户在应用层解决粘包问题的方法:
若是通信双方长时间没有数据往来(7200秒,即两小时),则会向对方发一个保活探测数据包,要求对方对这个数据包进行回复,若是收到回复,则连接正常,若是连续多次(9次,每次间隔75秒)没有收到回复,则认为连接断开(在Linux下输入:sysctl -a |grep keep 命令可以查看)
tcp异常连接断开的情况:
16位源/目的端口 16位数据报长度 16位校验和(二进制反码求和)
16位数据报长度 (0~65535,即最大64k-8个大小):用于指定整个udp数据报的长度(包含头部)
(16位数据报长度决定了一个udp协议的数据data长度不能大于64k-8,否则发送失败)
当数据长度大于64k-8时,就需要用户在应用层进行数据分包,将数据分成一个个小于64-8大小的数据段;
udp并不保证数据有序到达, 需要用户在应用层进行包序管理;
UDP实现的应用层协议:DHCP
功能:负责地址管理与路由选择
协议:IP协议
路由器
路由选择:在复杂的网络环境中,为每一条数据选择一条合适的路径
在网络中的IP地址不能随意分配,因为随意分配很容易造成IP地址冲突;
因此IP地址需要得到合理的管理才可以
一个路由器可以组件一个局域网,这时候路由器向局域网中的主机分配IP地址的时候,就必须带有自己网络的标识——网络号;这时候只需要将每个网络的网络号规范起来就可以避免IP地址冲突
在一个局域网中,路由器向主机分配IP地址,还要能够在局域网中表示这个主机,这个标识叫主机号
IP的组成:网络号+主机号
保证相邻的网络不能具有相同的网络号就可以尽可能的避免IP地址冲突
A类:低24位是主机号,A类网络地址主机号有2^24 0.0.0.0~127.255.255.255
B类:低16位是主机号,B类网络地址主机号有65535个,128.0.0.0~191.255.255.255
C类:低八位是主机号,C类网络地址主机号有256个,192.0.0.0~223.255.255.255
加入了一个字段叫子网掩码,通过子网掩码来对网络进行划分
子网掩码:
由一串连续的二进制1组成的一个无符号4个字节的整数
作用:
例题: 现在有一个C类网络地址,将这个C类网络划分出20个子网,请问每个子网掩码是多少,IP地址范围是多少,以及各自网络的网络号是多少?
C类网络地址有256个主机,平均划分20个子网,每个子网中主机号个数是256/20
每个子网中主机号个数是12,子网掩码是连续的1,因此12取反无法得到连续的1,在每个子网主机号能少不能多的情况下,为了保证子网掩码是连续的1,因此主机号只能是8,即2^3,得到最大主机号7能少不能多的情况下
在一个网络中,并不是所有的主机号都能分配给主机:
特殊IP地址: 127.0.0.1————本机虚拟回环网卡地址——用于本机的网络测试
在RFC1918中规定,用于组建私网的网段也不能随意使用
只有以下几个网段能够用于组建私网:10 . * . * . * 172.16 . * . * ~172.
路由选择:()
路由表:每个
MTU:最大传输单元
当udp数据长度,大于MTU ,小于64k-20-8时,链路层则不支持大于mtu大小数据传输,这时候网络先获取下层mtu大小,在网络层对数据进行分片
功能:负责相邻设备之间的数据传输;Ether;交换机
链路层协议字段:源MAC地址,目的MAC地址,上层协议类型,数据,帧尾
MAC地址:网络物理硬件地址,用于标识硬件设备
mtu对tcp协议的影响:tcp在传输层的时候就会获取mtu大小进行计算得到自己的mss大小,并于对方进行协商,取其中较小的一个作为传输大小,发送数据的时候从发送缓冲区中取出的数据大小就不会大于mss大小;tcp在传输层会自动进行数据分段,因此不会在网络层进行数据分片。
mtu对udp协议的影响:因为udp在传输层不会进行数据分段,因此当udp传输的数据大小,大于mtu但是小于64k-20-8的时候,数据会在网络层进行数据分片,分片了在对端就会进行分片重组,只要有一个分片出问题,都会导致整个udp数据报被丢弃;因此对于udp来说分片越多,传输就越危险
因此用户在应用层进行udp数据分包的时候最好就将数据大小控制在mtu-20-8
数据链路层的协议有好多种,最常用的就是以太网协议 ,该协议所使用的标准就是ETHERNET II标准 ,下图就是以太网协议标准定义的数据帧封装格式: