[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fevGmCK6-1633419450034)(java全占知识体系-计算机网络.assets/image-20210709100517785.png)]
HTTP的几种请求方法用途GET方法:发送一个请求来获取服务器上的某一些资源。
POST方法:向URL指定的资源提交数据或附加新的数据。
PUT方法:跟POST方法一样,可以向服务器提交数据,但是它们之间也所有不同,PUT指定了资源在服务器的位置,而POST没有哦。
HEAD方法:指请求页面的首部。
DELETe方法:删除服务器上的某资源。
OPTIONS方法:它用于获取当前URL所支持的方法,如果请求成功,在Allow的头包含类似GET,POST等的信息。
TRACE方法:用于激发一个远程的,应用层的请求消息回路。
CONNECT方法:把请求连接转换到TCP/TP通道。
HTTP中GET和POST的区别GET与POST是我们常用的两种HTTP Method,二者之间的区别主要包括如下五个方面:
- 从功能上讲,GET一般用来从服务器上获取资源,POST一般用来更新服务器上的资源;
- 从REST服务角度上说,GET是幂等的,即读取同一个资源,总是得到相同的数据,而POST不是幂等的,因为每次请求对资源的改变并不是相同的;进一步地,GET不会改变服务器上的资源,而POST会对服务器资源进行改变;
- 从请求参数形式上看,GET请求的数据会附在URL之后,即将请求数据放置在HTTP报文的 请求头中。
- 就安全性而言,POST的安全性要比GET的安全性高,因为GET请求提交的数据将明文出现在URL上,而且POST请求参数则被包装到请求体中,相对更安全。
- 从请求的大小看,GET请求的长度受限于浏览器或服务器对URL长度的限制,允许发送的数据量比较小,而POST请求则是没有大小限制的。
1、域名解析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gSyGPapr-1633419450036)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210807092204023.png)]
2、三次握手
3、建立TCP连接后发起http请求
4、服务器收到请求并响应HTTP请求
5、浏览器解析htm代码,并请求htm代码中的资源(如js、css图片等)
6、断开TCP连接
7、浏览器对页面进行渲染呈现给用户
TCP与UDP的区别,以及适用的范围
| UDP | TCP | |
|---|---|---|
| 是否连接 | 无连接 | 面向连接 |
| 是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
| 连接对象个数 | 支持一对一,一对多,多对一和多对多交互通信 | 只能是一对一通信 |
| 传输方式 | 面向报文 | 面向字节流 |
| 首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
| 适用场景 | 适用于实时应用(IP电话、视频会议、直播等) | 适用于要求可靠传输的应用,例如文件传输 |
- TCP向上层提供面向连接的可靠服务 ,UDP向上层提供无连接不可靠服务。
- 虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为
- 对数据准确性要求高,速度可以相对较慢的,可以选用TCP
首先是解决困扰人们的老大难问题:
一、什么是HTTP缓存 ?
http缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有“要请求资源”的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。
常见的http缓存只能缓存get请求响应的资源,对于其他类型的响应则无能为力,所以后续说的请求缓存都是指GET请求。
http缓存都是从第二次请求开始的。第一次请求资源时,服务器返回资源,并在respone header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,命中强缓存就直接200,否则就把请求参数加到request header头中传给服务器,看是否命中协商缓存,命中则返回304,否则服务器会返回新的资源。
http报文[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hny8aM9B-1633419450037)(java全占知识体系-计算机网络.assets/image-20210709150004109.png)]
web的性能指标- 延迟:指IP数据包从一个网络端点到另一个网络端点所花费的时间。(所花费时间在于往返时延,是延迟的时间的两倍)
- 带宽:只要带宽没有饱和,两个网络端点的连接会一次处理尽可能多的数据量(所以带宽可能会成为性能的瓶颈)
- 建立连接时间:在客户端和服务器之间建立连接往返数据(三次握手)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0WkbzGXA-1633419450038)(java全占知识体系-计算机网络.assets/image-20210704183652780.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KJDNnV68-1633419450039)(java全占知识体系-计算机网络.assets/image-20210704183753320.png)]
第一次挥手:A->B,A向B发出释放连接请求的报文,其中FIN(终止位) = 1,seq(序列号)=u;在A发送完之后,A的TCP客户端进入FIN-WAIT-1(终止等待1)状态。此时A还是可以进行收数据的
第二次挥手:B->A:B在收到A的连接释放请求后,随即向A发送确认报文。其中ACK=1,seq=v,ack(确认号) = u +1;在B发送完毕后,B的服务器端进入CLOSE_WAIT(关闭等待)状态。此时A收到这个确认后就进入FIN-WAIT-2(终止等待2)状态,等待B发出连接释放的请求。此时B还是可以发数据的。
(如果 B 直接跑路,则 A 永远处与这个状态。TCP 协议里面并没有对这个状态的处理,但 Linux 有,可以调整 tcp_fin_timeout 这个参数,设置一个超时时间。)
第三次挥手:B->A:当B已经没有要发送的数据时,B就会给A发送一个释放连接报文,其中FIN=1,ACK=1,seq=w,ack=u+1,在B发送完之后,B进入LAST-ACK(最后确认)状态。
第四次挥手:A->B;当A收到B的释放连接请求时,必须对此发出确认,其中ACK=1,seq=u+1,ack=w+1;A在发送完毕后,进入到TIME-WAIT (时间等待)状态。B在收到A的确认之后,进入到CLOSED(关闭)状态。在经过时间等待计时器设置的时间之后,A才会进入CLOSED状态。
关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。 服务器收到客户端的 FIN 报⽂时,先回⼀个 ACK 应答报⽂,⽽服务端可能还有数据需要处理和 发送,等服务端不再发送数据时,才发送 FIN 报⽂给客户端来表示同意现在关闭连接。
异常情况分析:
**如果A发给B的确认丢了,该如何?
A会超时重传这个ACK吗?不会!TCP不会为没有数据的ACK超时重传。
那该如何是好?B如果没有收到A的ACK,会超时重传自己的SYN同步信号,一直到收到A的ACK为止。
第一个包,即A发给B的SYN 中途被丢,没有到达B,怎么办?
A会周期性超时重传,直到收到B的确认
第二个包,即B发给A的SYN +ACK 中途被丢,没有到达A,怎么办?
B会周期性超时重传,直到收到A的确认
第三个包,即A发给B的ACK 中途被丢,没有到达B,怎么办?
A发完ACK,单方面认为TCP为 Established状态,而B显然认为TCP为Active状态:
a. 假定此时双方都没有数据发送,B会周期性超时重传,直到收到A的确认,收到之后B的TCP 连接也为 Established状态,双向可以发包。
b. 假定此时A有数据发送,B收到A的 Data + ACK,自然会切换为established 状态,并接受A的 Data。
c. 假定B有数据发送,数据发送不了,会一直周期性超时重传SYN + ACK,直到收到A的确认才可以发送数据。
总结:
握手的目的就是需要确认对方收到了自己的序列号
SYN的作用就是我发的这条消息,必须要要收到回复!如果一段时间内没有收到回复,我会重发
双方建立TCP连接时,会把自己的Seq发出去后,都需要确认对方收到了自己的序列号,我才认为连接成功,正常情况是需要通讯四次,但是可以优化为3次即可(即连接的被发起方,可以将自己的序列号消息和给发起方的回复消息合并为一条消息)
这么做有两个理由:
- 为了保证A发送的最后一个ACK报文段能够到达B。
A发送的这个ACK报文段有可能丢失,如果 B 没收到 A 发送来的确认报文,那么A就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。 - 防止“已经失效的连接请求报文段”出现在本链接中。
A在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接的时间内所产生的所有报文段都从网络中消失。这样下一个新的连接中就不会出现这种旧的连接请求报文段。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2WfU1Fdg-1633419450040)(java全占知识体系-计算机网络.assets/image-20210704183915927.png)]
- 服务端和客户端初始化 socket ,得到⽂件描述符;
- 服务端调⽤ bind ,将绑定在 IP 地址和端⼝;
- 服务端调⽤ listen ,进⾏监听;
- 服务端调⽤ accept ,等待客户端连接;
- 客户端调⽤ connect ,向服务器端的地址和端⼝发起连接请求;
- 服务端 accept 返回⽤于传输的 socket 的⽂件描述符;
- 客户端调⽤ write 写⼊数据;服务端调⽤ read 读取数据;
- 客户端断开连接时,会调⽤ close ,那么服务端 read 读取数据的时候,就会读取到了 EOF , 待处理完数据后,服务端调⽤ close ,表示连接关闭。
Linux内核中会维护两个队列: 未完成连接队列(SYN 队列):接收到⼀个 SYN 建⽴连接请求,处于 SYN_RCVD 状态; 已完成连接队列(Accpet 队列):已完成 TCP 三次握⼿过程,处于 ESTABLISHED 状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4wkVFmZX-1633419450041)(java全占知识体系-计算机网络.assets/image-20210704184018805.png)]
HTTP如何保存登录状态?(cookies,session,token)当我第一次调用用户名密码验证接口的时候,我需要输入账号、密码,服务器收到请求之后,就会根据账号去数据库取你的密码和你输入的密码进行比对,然后返回一个“密码正确”或“密码错误”。而问题在于当我第二次访问这个接口的时候,服务器依旧会执行他的职能:收到我发送的账号和密码,然后去数据库取数据进行比对后返回比对结果,对于服务器来说,每个请求不过是做了类似1+1是否等于2的判断然后返回结果而已。
我想要服务器能够记住我已经调用过一次登录接口并且以及成功了这个状态,应该怎么办?
cookie
cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。
Session
服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。
Token
Seesion每次认证用户发起请求时,服务器需要去创建一个记录来存储信息。当越来越多的用户发请求时,内存的开销也会不断增加。
基于Token的身份验证的过程如下:
-
用户通过用户名和密码发送请求。
-
程序验证。
-
程序返回一个签名的token 给客户端。
-
客户端储存token,并且每次用于每次发送请求。
-
服务端验证token并返回数据。
服务器创建session出来后,会把session的id号,以cookie的形式回写给客户机,这样,只要客户机的浏览器不关,再去访问服务器时,都会带着session的id号去,服务器发现客户机浏览器带session id过来了,就会使用内存中与之对应的session为之服务。
分布式sessionhttps://segmentfault.com/a/1190000022404396
OSI七层网络模型[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VAwStsX0-1633419450042)(java全占知识体系-计算机网络.assets/image-20210704184300356.png)]
数据链路层包括了硬件接口和协议ARP,RARP,这两个协议主要是用来建立送到物理层上的信息和接收从物理层上传来的信息;
网络层中的协议主要有IP,ICMP,IGMP等,由于它包含了IP协议模块,所以它是所有机遇TCP/IP协议网络的核心。在网络层中,IP模块完成大部分功能。ICMP和IGMP以及其他支持IP的协议帮助IP完成特定的任务,如传输差错控制信息以及主机/路由器之间的控制电文等。网络层掌管着网络中主机间的信息传输。
传输层上的主要协议是TCP和UDP。正如网络层控制着主机之间的数据传递,传输层控制着那些将要进入网络层的数据。两个协议就是它管理这些数据的两种方式:TCP是一个基于连接的协议(还记得我们在网络基础中讲到的关于面向连接的服务和面向无连接服务的概念吗?忘了的话,去看看);UDP则是面向无连接服务的管理方式的协议。
应用层位于协议栈的顶端,它的主要任务就是应用了。上面的协议当然也是为了这些应用而设计的,具体说来一些常用的协议功能如下:
应用层常用协议Telnet:提供远程登录(终端仿真)服务,好象比较古老的BBS就是用的这个登陆。
FTP :提供应用级的文件传输服务,说的简单明了点就是远程文件访问等等服务;
SMTP:不用说拉,天天用到的电子邮件协议。
TFTP:提供小而简单的文件传输服务,实际上从某个角度上来说是对FTP的一种替换(在文件特别小并且仅有传输需求的时候)。
SNTP:简单网络管理协议。看名字就不用说什么含义了吧。
DNS:域名解析服务,也就是如何将域名映射城IP地址的协议。
HTTP:不知道各位对这个协议熟不熟悉啊?这是超文本传输协议,你之所以现在能看到网上的图片,动画,音频,等等,都是仰仗这个协议在起作用啊!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YDcycc4w-1633419450043)(java全占知识体系-计算机网络.assets/image-20210704185228614.png)]
HTTP 与 HTTPS区别- HTTP 是超⽂本传输协议,信息是明⽂传输,存在安全⻛险的问题。HTTPS 则解决 HTTP 不安全的 缺陷,在 TCP 和 HTTP ⽹络层之间加⼊了 SSL/TLS 安全协议,使得报⽂能够加密传输。
- HTTP 连接建⽴相对简单, TCP 三次握⼿之后便可进⾏ HTTP 的报⽂传输。⽽ HTTPS 在 TCP 三 次握⼿之后,还需进⾏ SSL/TLS 的握⼿过程,才可进⼊加密报⽂传输。
- HTTP 的端⼝号是 80,HTTPS 的端⼝号是 443。
- HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。
**非对称秘钥:**非对称加密算法需要两个密钥:公开秘钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
首先需要小B把自己的公钥key1发送给小A:
小A收到小B的公钥key1以后,小A自己生成一个对称加密的秘钥key2,并且用key1对key2进行加密,发送给小B:
小B接收到了小A发送给自己的非对称加密的私钥,然后用自己的私钥解开key1拿到里面key2,然后就可以用key2进行加密通信了。在通信中,即使中间人拿到key1,但是不知道key1的私钥是什么,也无法得到key2。
这种情况会绝对安全的吗?
并不是,中间人虽然不知道小B的key1私钥是什么,但是截取了小B的key1之后,却可以偷天换日,自己生成一对公钥和私钥,然后把自己的公钥key3发送给小A。
小A不知道公钥key1被偷偷换过,以为key3就是小B发送的公钥,所以用key3加密自己生成的非对称密钥key2发送给小B
这一次再次被中间人截取,中间人先用自己的私钥解密key3拿到key2,然后再用截取小B的key1对key2进行加密,发送给小B。
这样中加人再次拿到了key2.
**对称秘钥:**对称密钥加密又叫专用密钥加密,即发送和接收数据的双方必使用相同的密钥对明文进行加密和解密运算。通常有两种模式:流加密和分组加密。这个时候需要加入第三方,一个权威的证书颁发机构(CA)来解决。那么到底怎么解决的呢?
1 作为服务端到的小B,首先把自己的公钥key1发送证书颁发机构,向证书颁发机构申请证书。
2 证书颁发机构自己也有一对公钥和私钥,机构利用自己的私钥加密key1,并且通过服务端的网址等信息生成一个证书签名,证书签名同样经过私钥加密,然后把证书发送给小B。
3 当小A向小B发送请求通信的时候,小B不在把自己的公钥key1发送回去,而是把自己申请的证书发送给小A。
4 小A拿到证书后,第一件事就是验证证书的真伪,因为各大浏览器已经维护了所有权威证书机构的名称和公钥。所以小A只需要是哪家机构的证书,就可以从本地找到对应机构的公钥,解密出证书的签名,接下来销毁按照同样的签名规则,自己也生成一个证书签名,如果来个签名一致,说明这个证书是有效的。验证成功后,小A就可以利用机构的公钥解密出key1。
HTTPS 解决了 HTTP 的哪些问题?HTTP 由于是明⽂传输,所以安全上存在以下三个⻛险:
- 窃听⻛险,⽐如通信链路上可以获取通信内容,⽤户号容易没。
- 篡改⻛险,⽐如强制植⼊垃圾⼴告,视觉污染,⽤户眼容易瞎。
- 冒充⻛险,⽐如冒充淘宝⽹站,⽤户钱容易没。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B3KPVV3G-1633419450044)(java全占知识体系-计算机网络.assets/image-20210704185651093.png)]
ARP是地址解析协议,简单语言解释一下工作原理。ARP 实现由 IP 地址得到 MAC 地址。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tzBeau7I-1633419450045)(E:/OneDrive/文档/JavaXzM/offer最终冲刺班/java全占知识体系-计算机网络.assets/v2-f1e279c7d218acee64f46c22ae4c5a5b_720w.jpg)]
1:首先,每个主机都会在自己的ARP缓冲区中建立一个ARP列表,以表示IP地址和MAC地址之间的对应关系。
1:首先,每个主机都会在自己的ARP缓冲区中建立一个ARP列表,以表示IP地址和MAC地址之间的对应关系。
2:当源主机要发送数据时,首先检查ARP列表中是否有对应IP地址的目的主机的MAC地址,如果有,则直接发送数据,如果没有,就向本网段的所有主机发送ARP数据包,该数据包包括的内容有:源主机IP地址,源主机MAC地址,目的主机的IP地址。
3:当本网络的所有主机收到该ARP数据包时,首先检查数据包中的IP地址是否是自己的IP地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的IP和MAC地址写入到ARP列表中,如果已经存在,则覆盖,然后将自己的MAC地址写入ARP响应包中,告诉源主机自己是它想要找的MAC地址。
4:源主机收到ARP响应包后。将目的主机的IP和MAC地址写入ARP列表,并利用此信息发送数据。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
广播发送ARP请求,单播发送ARP响应。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-18OtedJh-1633419450046)(E:/OneDrive/文档/JavaXzM/offer最终冲刺班/java全占知识体系-计算机网络.assets/v2-d33dddc6562088525b55ce75d0b4a7dd_720w.jpg)]
TCP协议如何来保证传输的可靠性- 数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时TCP发送数据端超时后会重发数据;
- 对失序数据包重排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。TCP将对失序数据进行重新排序,然后才交给应用层;
- 丢弃重复数据:对于重复数据,能够丢弃重复数据;
- 应答机制:当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒;
- 超时重发:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;
- 流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP使用的流量控制协议是可变大小的滑动窗口协议。
- TCP面向连接,传输数据之前要需要建立会话。UDP是无连接的。
- TCP提供可靠传输,保证数据不丢包、不重复且按顺序到达;UDP只尽努力交付,不保证可靠交付
- TCP提供了拥塞控制;UDP不提供
- TCP是面向字节流的;UDP面向报文。
- TCP只支持点到点通信;UDP支持一对一、一对多、多对多的交互通信。
- TCP首部开销大20字节,UDP首部开销小8字节。
- UDP的首部格式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v8UK9iOR-1633419450047)(E:/OneDrive/文档/JavaXzM/offer最终冲刺班/java全占知识体系-计算机网络.assets/v2-872c22b87781c30e50fc92efbc79cb01_720w.jpg)]
-
- TCP的首部格式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-twD5RgGQ-1633419450049)(E:/OneDrive/文档/JavaXzM/offer最终冲刺班/java全占知识体系-计算机网络.assets/v2-f37366faf61a44f74292c3bff999f195_720w.jpg)]
TCP和UDP分别对应的常见的端口以及应用层协议
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bH51NDnF-1633419450050)(E:/OneDrive/文档/JavaXzM/offer最终冲刺班/java全占知识体系-计算机网络.assets/v2-3296ddbc2c647d656585a3bb00f93c65_720w.jpg)]
1). TCP对应的应用层协议
- FTP:定义了文件传输协议,使用21端口。常说某某计算机开了FTP服务便是启动了文件传输服务。下载文件,上传主页,都要用到FTP服务。
- Telnet:它是一种用于远程登陆的端口,用户可以以自己的身份远程连接到计算机上,通过这种端口可以提供一种基于DOS模式下的通信服务。如以前的BBS是-纯字符界面的,支持BBS的服务器将23端口打开,对外提供服务。
- SMTP:定义了简单邮件传送协议,现在很多邮件服务器都用的是这个协议,用于发送邮件。如常见的免费邮件服务中用的就是这个邮件服务端口,所以在电子邮件设置-中常看到有这么SMTP端口设置这个栏,服务器开放的是25号端口。
- POP3:它是和SMTP对应,POP3用于接收邮件。通常情况下,POP3协议所用的是110端口。也是说,只要你有相应的使用POP3协议的程序(例如Fo-xmail或Outlook),就可以不以Web方式登陆进邮箱界面,直接用邮件程序就可以收到邮件(如是163邮箱就没有必要先进入网易网站,再进入自己的邮-箱来收信)。
- HTTP:从Web服务器传输超文本到本地浏览器的传送协议。
2). UDP对应的应用层协议
- DNS:用于域名解析服务,将域名地址转换为IP地址。DNS用的是53号端口。
- SNMP:简单网络管理协议,使用161号端口,是用来管理网络设备的。由于网络设备很多,无连接的服务就体现出其优势。
- TFTP(Trival File Transfer Protocal):简单文件传输协议,该协议在熟知端口69上使用UDP服务。
状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值: 1xx:指示信息–表示请求已接收,继续处理 2xx:成功–表示请求已被成功接收、理解、接受 3xx:重定向–要完成请求必须进行更进一步的操作 4xx:客户端错误–请求有语法错误或请求无法实现 5xx:服务器端错误–服务器未能实现合法的请求
常见状态代码、状态描述、说明:
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间
可能恢复正常
泛洪攻击
这幅图呢就是TCP的通信的三次握手,如果说攻击端,发送完第一次握手的数据后,然后就"消失"了,那么服务器就会不断的发送第二次握手的数据,可是攻击端的人找不到了。于是,服务器的资源大量被消耗,直到死机为止。当然了,如果要完全弄懂机制,需要对TCP有相当深入的了解。
现在回到我们的原题:SYN泛洪攻击,其实这个攻击主要利用的就是TCP三次握手机制的缺陷。
TCP SYN泛洪主要发生在OSI的第四层,(关于这个OSI我会在后面的文章给大家讲述。)利用了这个TCP三次握手的特性。
A(攻击者)发送TCP SYN,SYN是TCP三次握手中的第一个数据包,而当这个服务器返回ACK以后,A不再进行确认,那这个连接就处在了一个挂起的状态,也就是半连接的意思,那么服务器收不到再确认的一个消息,还会重复发送ACK给A。这样一来就会更加浪费服务器的资源。A就对服务器发送非法大量的这种TCP连接,由于每一个都没法完成握手的机制,所以它就会消耗服务器的内存最后可能导致服务器死机,就无法正常工作了。更进一步说,如果这些半连接的握手请求是恶意程序发出,并且持续不断,那么就会导致服务端较长时间内丧失服务功能——这样就形成了DoS攻击。这种攻击方式就称为SYN泛洪攻击。
那么我们如何去防范这种SYN攻击呢?
其实最常用的一个手段就是优化主机系统设置。比如降低SYN timeout时间,使得主机尽快释放半连接的占用或者采用SYN cookie设置,如果短时间内收到了某个IP的重复SYN请求,我们就认为受到了攻击。我们合理的采用防火墙设置等外部网络也可以进行拦截。
TCP流量控制、拥塞控制 一、流量控制什么是流量控制?流量控制的目的?
如果发送者发送数据过快,接收者来不及接收,那么就会有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。流量控制根本目的是防止分组丢失,它是构成TCP可靠性的一方面。
如何实现流量控制?
由滑动窗口协议(连续ARQ协议)实现。滑动窗口协议既保证了分组无差错、有序接收,也实现了流量控制。主要的方式就是接收方返回的 ACK 中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送。
流量控制引发的死锁?怎么避免死锁的发生?
当发送者收到了一个窗口为0的应答,发送者便停止发送,等待接收者的下一个应答。但是如果这个窗口不为0的应答在传输过程丢失,发送者一直等待下去,而接收者以为发送者已经收到该应答,等待接收新数据,这样双方就相互等待,从而产生死锁。
为了避免流量控制引发的死锁,TCP使用了持续计时器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生。
拥塞控制:拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况;常用的方法就是:( 1 )慢开始、拥塞避免( 2 )快重传、快恢复。
流量控制:流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收,防止分组丢失的。
三、拥塞控制的算法我们在开始假定:1、数据是单方向传递,另一个窗口只发送确认;2、接收方的缓存足够大,因此发送方的大小的大小由网络的拥塞程度来决定。
(一)慢开始算法:
发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到接受方的接收能力,发送窗口可能小于拥塞窗口。
慢开始算法的思路就是,不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。
这里用报文段的个数作为拥塞窗口的大小举例说明慢开始算法,实际的拥塞窗口大小是以字节为单位的。如下图:
从上图可以看到,一个传输轮次所经历的时间其实就是往返时间RTT,而且没经过一个传输轮次(transmission round),拥塞窗口cwnd就加倍。
为了防止cwnd增长过大引起网络拥塞,还需设置一个慢开始门限ssthresh状态变量。ssthresh的用法如下:当cwnd
当cwnd=ssthresh时,慢开始与拥塞避免算法任意
注意,这里的“慢”并不是指cwnd的增长速率慢,而是指在TCP开始发送报文段时先设置cwnd=1,然后逐渐增大,这当然比按照大的cwnd一下子把许多报文段突然注入到网络中要“慢得多”。
(二)拥塞避免算法:
拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口按线性规律缓慢增长。
无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有按时收到确认,虽然没有收到确认可能是其他原因的分组丢失,但是因为无法判定,所以都当做拥塞来处理),就把慢开始门限ssthresh设置为出现拥塞时的发送窗口大小的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。
整个拥塞控制的流程如下图:
(1)拥塞窗口cwnd初始化为1个报文段,慢开始门限初始值为16
(2)执行慢开始算法,指数规律增长到第4轮,即cwnd=16=ssthresh,改为执行拥塞避免算法,拥塞窗口按线性规律增长
(3)假定cwnd=24时,网络出现超时(拥塞),则更新后的ssthresh=12,cwnd重新设置为1,并执行慢开始算法。当cwnd=12=ssthresh时,改为执行拥塞避免算法
关于 乘法减小(Multiplicative Decrease)和加法增大(Additive Increase):
“乘法减小”指的是无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞,就把慢开始门限ssthresh设置为出现拥塞时的发送窗口大小的一半,并执行慢开始算法,所以当网络频繁出现拥塞时,ssthresh下降的很快,以大大减少注入到网络中的分组数。“加法增大”是指执行拥塞避免算法后,使拥塞窗口缓慢增大,以防止过早出现拥塞。常合起来成为AIMD算法。
注意:“拥塞避免”并非完全能够避免了阻塞,而是使网络比较不容易出现拥塞。
(三)快重传算法:
快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方,可提高网络吞吐量约20%)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。如下图:
(四)快恢复算法:
快重传配合使用的还有快恢复算法,有以下两个要点:
当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半(为了预防网络发生拥塞)。但是接下去并不执行慢开始算法
考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh减半后的值,然后执行拥塞避免算法,使cwnd缓慢增大。如下图:TCP Reno版本是目前使用最广泛的版本。
注意:在采用快恢复算法时,慢开始算法只是在TCP连接建立时和网络出现超时时才使用
UDP实现可靠数据传输UDP没有Delievery Garuantee,也没有顺序保证,所以如果你要求你的数据发送与接受既要高效,又要保证有序,收包确认等,你就****需要在UDP协议上构建自己的协议****。比如RTCP,RTP协议就是在UPD协议之上专门为H.323协议簇上的IP电话设计的一种介于传输层和应用层之间的协议。
三种使用UDP进行可靠数据传输的协议
*RUDP*
*RTP*
*UDT*
SSL协议的握手过程先用语言来阐述下:
- 第一步:爱丽丝给出支持SSL协议版本号,一个客户端随机数(Client random,请注意这是第一个随机数),客户端支持的加密方法等信息;
- 第二步:鲍勃收到信息后,确认双方使用的加密方法,并返回数字证书,一个服务器生成的随机数(Server random,注意这是第二个随机数)等信息;
- 第三步:爱丽丝确认数字证书的有效性,然后生成一个新的随机数(Premaster secret),然后使用数字证书中的公钥,加密这个随机数,发给鲍勃。
- 第四步:鲍勃使用自己的私钥,获取爱丽丝发来的随机数(即Premaster secret);(第三、四步就是非对称加密的过程了)
- 第五步:爱丽丝和鲍勃通过约定的加密方法(通常是AES算法),使用前面三个随机数,生成对话密钥,用来加密接下来的通信内容;
俗话说一图胜前言,我画了一个图来说明这个过程:
OK,整个进行数据加密的过程结束。我们再来回忆下内容:
- CA机构颁发数字证书给鲍勃;
- 爱丽丝和鲍勃进行SSL握手,爱丽丝通过数字证书确定鲍勃的身份;
- 爱丽丝和鲍勃传递三个随机数,第三个随机数通过非对称加密算法进行传递;
- 爱丽丝和鲍勃通过一个对称加密算法生成一个对话密钥,加密接下来的通信内容。
在 Linux 的源代码中,网络设备驱动对应的逻辑位于 driver/net/ethernet , 其中 intel 系列网卡的 驱动在 driver/net/ethernet/intel 目录下。协议栈模块代码位于 kernel 和 net 目录。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lbws85Wd-1633419450056)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811140234014.png)]
内核和网络设备驱动是通过中断的方式来处理的。
当设备上有数据到达的时候,会给 CPU 的相关引脚 上触发一个电压变化,以通知 CPU 来处理数据。
对于网络模块来说,由于处理过程比较复杂和耗时, **如果在中断函数中完成所有的处理,将会导致中断处理函数(优先级过高)将过度占据 CPU ,将导致 CPU 无法响应其它设备,例如鼠标和键盘的消息。因此Linux中断处理函数是分上半部和下半部的。**上 半部是只进行最简单的工作,快速处理然后释放 CPU ,接着 CPU 就可以允许其它中断进来。剩下将绝 大部分的工作都放到下半部中,可以慢慢从容处理。2.4 以后的内核版本采用的下半部实现方式是软中 断,由 ksoftirqd 内核线程全权处理。和硬中断不同的是,硬中断是通过给 CPU 物理引脚施加电压变 化,而软中断是通过给内存中的一个变量的二进制值以通知软中断处理程序。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0EXLhLBX-1633419450057)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811140356514.png)]
- 当网卡上收到数据以后,Linux 中第一个工作的模块是网络驱动。 网络驱动会以 DMA 的方式把网卡上 收到的帧写到内存里。再向 CPU 发起一个中断,以通知 CPU 有数据到达。
- 第二,当 CPU 收到中断请 求后,会去调用网络驱动注册的中断处理函数。 网卡的中断处理函数并不做过多工作,发出软中断请 求,然后尽快释放 CPU。
- ksoftirqd 检测到有软中断请求到达,调用 poll 开始轮询收包,收到后交由各 级协议栈处理。对于 udp 包来说,会被放到用户 socket 的接收队列中。
Linux 驱动,内核协议栈等等模块在具备接收网卡数据包之前,要做很多的准备工作才行。比如要提前 创建好ksoftirqd内核线程,要注册好各个协议对应的处理函数,网卡设备子系统要提前初始化好,网卡 要启动好。只有这些都Ready之后,我们才能真正开始接收数据包。那么我们现在来看看这些准备工作 都是怎么做的。
创建ksoftirqd内核进程
Linux 的软中断都是在专⻔的内核线程(ksoftirqd)中进行的,因此我们非常有必要看一下这些进程是 怎么初始化的,这样我们才能在后面更准确地了解收包过程。该进程数量不是 1 个,而是 N 个,其中 N 等于你的机器的核数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mA3IBYO7-1633419450059)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811140715769.png)]
迎接数据的到来 硬中断处理首先当数据帧从网线到达网卡上的时候,第一站是网卡的接收队列。网卡在分配给自己的 RingBuffer 中寻找可用的内存位置,找到后 DMA 引擎会把数据 DMA 到网卡之前关联的内存里,这个时候 CPU 都是无感的。当 DMA 操作完成以后,网卡会向 CPU 发起一个硬中断,通知 CPU 有数据到达。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZSUvsH3Z-1633419450060)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811140840963.png)]
软中断处理注意:当RingBuffer满的时候,新来的数据包将给丢弃。ifconfig查看网卡的时候,可以里面有个 overruns,表示因为环形队列满被丢弃的包。如果发现有丢包,可能需要通过ethtool命令来加大 环形队列的⻓度。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7T6REhfd-1633419450062)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811140908356.png)]
网络协议栈处理netif_receive_skb 函数会根据包的协议,假如是 udp 包,会将包依次送到 ip_rcv(), udp_rcv() 协 议处理函数中进行处理。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YFjSR9N3-1633419450063)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811141243092.png)]
总结首先在开始收包之前,Linux 要做许多的准备工作:
- 创建ksoftirqd线程,为它设置好它自己的线程函数,后面就指望着它来处理软中断呢。
- 协议栈注册,linux要实现许多协议,比如arp,icmp,ip,udp,tcp,每一个协议都会将自己 的处理函数注册一下,方便包来了迅速找到对应的处理函数
- 网卡驱动初始化,每个驱动都有一个初始化函数,内核会让驱动也初始化一下。在这个初始化过 程中,把自己的DMA准备好,把NAPI的poll函数地址告诉内核
- 启动网卡,分配RX,TX队列,注册中断对应的处理函数
当数据到到来了以后,第一个迎接它的是网卡(我去,这不是废话么):
- 网卡将数据帧 DMA 到内存的 RingBuffer 中,然后向 CPU 发起中断通知 CPU 响应中断请求,调用网卡启动时注册的中断处理函数
- 中断处理函数几乎没干啥,就发起了软中断请求
- 内核线程 ksoftirqd 线程发现有软中断请求到来,先关闭硬中断
- ksoftirqd 线程开始调用驱动的 poll 函数收包
- poll 函数将受到的包送到协议栈注册的 ip_rcv 函数中
- ip_rcv 函数再讲包送到 udp_rcv 函数中(对于 tcp 包就送到 tcp_rcv )
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Et9us4v-1633419450064)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811143041020.png)]
等待接收消息接着我们来看 recv 函数依赖的底层实现。首先通过 strace 命令跟踪,可以看到 clib 库函数 recv 会执
行到 recvfrom 系统调用。
进入系统调用后,用户进程就进入到了内核态,通过执行一系列的内核协议层函数,然后到 socket 对 象的接收队列中查看是否有数据,没有的话就把自己添加到 socket 对应的等待队列里。最后让出 CPU,操作系统会选择下一个就绪状态的进程来执行。 整个流程图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZ8x4HgR-1633419450065)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811143457206.png)]
如果没有收到数据,或者收到不足够多,则调用 sk_wait_data 把当前进程阻塞掉。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-atFoM9VY-1633419450066)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811143632830.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oViQKPLy-1633419450066)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811143657841.png)]
软中断模块接着我们再转换一下视⻆,来看负责接收和处理数据包的软中断这边。前文看到了关于网络包到网卡后 是怎么被网卡接收,最后在交由软中断处理的。我们今天直接从 tcp 协议的接收函数 tcp_v4_rcv 看 起。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wmDm1Alp-1633419450067)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811143753446.png)]
软中断(也就是 Linux 里的 ksoftirqd 进程)里收到数据包以后,发现是 tcp 的包的话就会执行到 tcp_v4_rcv 函数。接着走,如果是 ESTABLISH 状态下的数据包,则最终会把数据拆出来放到对应 socket 的接收队列中。然后调用 sk_data_ready 来唤醒用户进程。
在 tcp_v4_rcv 中首先根据收到的网络包的 header 里的 source 和 dest 信息来在本机上查询对应的 socket。找到以后,我们直接进入接收的主体函数 tcp_v4_do_rcv 来看。
总结好了,我们把上面的流程总结一下。 内核在通知网络包的运行环境分两部分:
第一部分是我们自己代码所在的进程,我们调用的 socket() 函数会进入内核态创建必要内核对 象。 recv() 函数在进入内核态以后负责查看接收队列,以及在没有数据可处理的时候把当前进 程阻塞掉,让出 CPU。
第二部分是硬中断、软中断上下文(系统进程 ksoftirqd)。在这些组件中,将包处理完后会放 到 socket 的接收队列中。然后再根据 socket 内核对象找到其等待队列中正在因为等待而被阻 塞掉的进程,然后把它唤醒。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EmpFpfOV-1633419450068)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210811144200477.png)]
每次一个进程专⻔为了等一个 socket 上的数据就得被从 CPU 上拿下来。然后再换上另一个进程。等到 数据 ready 了,睡眠的进程又会被唤醒。总共两次进程上下文切换开销,根据之前的测试来看,每一 次切换大约是 3-5 us(微秒)左右。 如果是网络 IO 密集型的应用的话,CPU 就不停地做进程切换这种无 用功。
在服务端⻆色上,这种模式完全没办法使用。因为这种简单模型里的 socket 和进程是一对一的。我们 现在要在单台机器上承载成千上万,甚至十几、上百万的用户连接请求。如果用上面的方式,那就得为 每个用户请求都创建一个进程。 相信你在无论多原始的服务器网络编程里,都没⻅过有人这么干吧。
如果让我给它起一个名字的话,它就叫单路不复用(⻜哥自创名词)。那么有没有更高效的网络 IO 模 型呢? 当然有,那就是你所熟知的 select、poll 和 epoll了。 下次⻜哥再开始拆解 epoll 的实现源码, 敬请期待!
这种模式在客户端⻆色上,现在还存在使用的情形。因为你的进程可能确实得等 Mysql 的数据返回成功 之后,才能渲染⻚面返回给用户,否则啥也干不了。
注意一下,我说的是⻆色,不是具体的机器。 例如对于你的 php/java/golang 接口机,你接收 用户请求的时候,你是服务端⻆色。但当你再请求 redis 的时候,就变为客户端⻆色了。
不过现在有一些封装的很好的网络框架例如 Sogou Workflow,Golang 的 net 包等在网络客户端⻆色 上也早已摒弃了这种低效的模式!
IO 多路复用 EPOLL 内部实现进程在 Linux 上是一个开销不小的家伙,先不说创建,光是上下文切换一次就得几个微秒。所以为了高 效地对海量用户提供服务,必须要让一个进程能同时处理很多个 tcp 连接才行。现在假设一个进程保持 了 10000 条连接,那么如何发现哪条连接上有数据可读了、哪条连接可写了 ?
我们当然可以采用循环遍历的方式来发现 IO 事件,但这种方式太低级了。我们希望有一种更高效的机 制,在很多连接中的某条上有 IO 事件发生的时候直接快速把它找出来。其实这个事情 Linux 操作系统 已经替我们都做好了,它就是我们所熟知的 IO 多路复用机制。 这里的复用指的就是对进程的复用。
在 Linux 上多路复用方案有 select、poll、epoll。 它们三个中 epoll 的性能表现是最优秀的,能支持 的并发量也最大。所以我们今天把 epoll 作为要拆解的对象,深入揭秘内核是如何实现多路的 IO 管理 的。
我们来用一幅图总结一下 epoll 的整个工作路程。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vIYZTJvd-1633419450069)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210813083732587.png)]
其中软中断回调的时候回调函数也整理一下: sock_def_readable: sock 对象初始化时设置的
=> ep_poll_callback : epoll_ctl 时添加到 socket 上的
=> default_wake_function: epoll_wait 是设置到 epoll上的
总结下,epoll 相关的函数里内核运行环境分两部分:
用户进程内核态。进行调用 epoll_wait 等函数时会将进程陷入内核态来执行。这部分代码负责 查看接收队列,以及负责把当前进程阻塞掉,让出 CPU。 硬软中断上下文。在这些组件中,将包从网卡接收过来进行处理,然后放到 socket 的接收队 列。对于 epoll 来说,再找到 socket 关联的 epitem,并把它添加到 epoll 对象的就绪链表 中。 这个时候再捎带检查一下 epoll 上是否有被阻塞的进程,如果有唤醒之。
为了介绍到每个细节,本文涉及到的流程比较多,把阻塞都介绍进来了。
但其实在实践中,只要活儿足够的多,epoll_wait 根本都不会让进程阻塞。用户进程会一直干活,一直 干活,直到 epoll_wait 里实在没活儿可干的时候才主动让出 CPU。这就是 epoll 高效的地方所在!
内核如何高效使用内存[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JjzaQjnr-1633419450070)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210813093323039.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SMr58lXl-1633419450071)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210813093400173.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xSIXc0so-1633419450072)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210813093415303.png)]
一段数据流从应用程序发送端,一直到应用程序接收端,总共经过了多少次拷贝?我的本意可以用文稿中的一张图来表示,还记得 TCP/IP 层次模型么?我想通过这么一个问题,来展示 TCP/IP 分层的思想。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SLpgpJGV-1633419450073)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210818105956205.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ayFWSZhO-1633419450074)(/Users/xuzhiming/Library/Application Support/typora-user-images/image-20210818110244640.png)]
让我们先看发送端,当应用程序将数据送到发送缓冲区时,调用的是 send 或 write 方法,如果缓存中没有空间,系统调用就会失败或者阻塞。我们说,这个动作事实上是一次”显式拷贝“。而在这之后,数据将会按照 TCP/IP 的分层再次进行拷贝,这层的拷贝对我们来说就不是显式的了。
接下来轮到 TCP 协议栈工作,创建 Packet 报文,并把报文发送到传输队列中(qdisc),传输队列是一个典型的 FIFO 队列,队列的最大值可以通过 ifocnfig 命令输出的 txqueuelen 来查看。通常情况下,这个值有几千报文大小。
TX ring 在网络驱动和网卡之间,也是一个传输请求的队列。
网卡作为物理设备工作在物理层,主要工作是把要发送的报文保存到内部的缓存中,并发送出去。
接下来再看接收端,报文首先到达网卡,由网卡保存在自己的接收缓存中,接下来报文被发送至网络驱动和网卡之间的 RX ring,网络驱动从 RX ring 获取报文 ,然后把报文发送到上层。
这里值得注意的是,网络驱动和上层之间没有缓存,因为网络驱动使用 Napi 进行数据传输。因此,可以认为上层直接从 RX ring 中读取报文。
最后,报文的数据保存在套接字接收缓存中,应用程序从套接字接收缓存中读取数据。
这就是数据流从应用程序发送端,一直到应用程序接收端的整个历程,你看懂了吗?
贝?
我的本意可以用文稿中的一张图来表示,还记得 TCP/IP 层次模型么?我想通过这么一个问题,来展示 TCP/IP 分层的思想。
[外链图片转存中…(img-SLpgpJGV-1633419450073)]
[外链图片转存中…(img-ayFWSZhO-1633419450074)]
让我们先看发送端,当应用程序将数据送到发送缓冲区时,调用的是 send 或 write 方法,如果缓存中没有空间,系统调用就会失败或者阻塞。我们说,这个动作事实上是一次”显式拷贝“。而在这之后,数据将会按照 TCP/IP 的分层再次进行拷贝,这层的拷贝对我们来说就不是显式的了。
接下来轮到 TCP 协议栈工作,创建 Packet 报文,并把报文发送到传输队列中(qdisc),传输队列是一个典型的 FIFO 队列,队列的最大值可以通过 ifocnfig 命令输出的 txqueuelen 来查看。通常情况下,这个值有几千报文大小。
TX ring 在网络驱动和网卡之间,也是一个传输请求的队列。
网卡作为物理设备工作在物理层,主要工作是把要发送的报文保存到内部的缓存中,并发送出去。
接下来再看接收端,报文首先到达网卡,由网卡保存在自己的接收缓存中,接下来报文被发送至网络驱动和网卡之间的 RX ring,网络驱动从 RX ring 获取报文 ,然后把报文发送到上层。
这里值得注意的是,网络驱动和上层之间没有缓存,因为网络驱动使用 Napi 进行数据传输。因此,可以认为上层直接从 RX ring 中读取报文。
最后,报文的数据保存在套接字接收缓存中,应用程序从套接字接收缓存中读取数据。
这就是数据流从应用程序发送端,一直到应用程序接收端的整个历程,你看懂了吗?



