计算机网络
1.传输层
TCP
1.0 TCP的特点
提供可靠传输,实行顺序控制或重发控制机制。具有流控制、拥塞控制、提高网络利用率等众多功能。
充分实现了数据传输时各种控制功能,可以进行丢包时的重发机制,还可以对次序乱掉的分包进行顺序控制。
TCP 的特点及其目的
TCP 通过检验和
、连接管理
、确认应答
、 重发超时机制
、序列号机制
、以段为单位发送数据
、窗口控制
、流控制
、等机制进行可靠传输。
检验和
:这个原理和 MD5 完整性校验一致,目检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
连接管理
:采用三次握手的方式建立可靠的通信传输,
确认应答
: 确认应答就是会发送一条已经收到段的应答消息。
重发超时机制
:这个含义在上面的序列号机制已经提到,当发送端长时间没有接收到,确认信息时,则会对该条报文进行确认,因为此时他认为,是报文发送失败。所以这个超时时间的设定就显得尤为重要。TCP采用了一个很巧妙的方法,那就是每次发包时都会,计算往返时间及其偏差,重传的时间就是比两者之和稍大一点的值。
RTT:往返时间
RTO:重发时间
,重发时间略大于多次RTT的平均值
序列号机制
:当发送的数据到达接收主机时,接收端主机会返回已经收到的ACK确认号,确认应答。但是确认应答有可能出现以下这种情况,报文发送时丢失,确认应答信息丢失
。这样就可能会导致发送端一直重发报文。一般情况下,就发送端会等待一段时间后,如果没有收到确认应答,则会进行重发,但是我们也会遇到这种情况,当我们因为网络延迟之后,在我们发送方重传了报文之后,才接收到确认应答的信息,所以这样接收端就会收到无休止的重复包,所以这时候我们需要引入序列号机制,就是给每一个TCP报文添加一个序列号,告知发送方,我收到了哪条信息,下次传输时应该传输哪个报文。
以MSS为单位发送数据
:建立TCP连接的同时,也可以确定发送数据包的单位,我们称其为最大发送长度MSS,该值是在三次握手时计算得出的,会在两者之间选择一个都可接受的最小值
,TCP在发送数据时,重发时是以MSS为单位进行发送的。
流量控制,利用窗口控制提高速度
:上面我们提到的,每次都要进行确认,如果往返时间较长,这会大大降低效率,所以TCP引入了窗口的概念,这样我们就可以使确认的不是每个分段,而是以最大的单位进行确认,就是发完一个段之后,不用等到确认信息,继续发段。窗口大小就是无需等待确认应答, 而可以发送数据的最大值
。当然这种情况也会出现丢失段的情况,因为TCP有序列号机制,所以知道哪些段需要重发,发送方的缓冲区,会将待重发的段保存到缓冲区内,知道收到确认应答。
流控制
:可以让发送端根据接收端的接收实力进行发送。接收端会向发送端发送可以接收的数据大小。另外为了防止接收不到窗口更新通知,发送端则会时不时发送一个窗口探测的数据来获取窗口信息。
拥塞控制
:
为了进行拥塞控制,TCP 发送方要维持一个 拥塞窗口(cwnd) 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个
。 TCP的拥塞控制采用了四种算法,即 慢开始 、 拥塞避免 、快重传 和 快恢复 。 慢开始: 慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的符合情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd初始值为1,每经过一个传播轮次,cwnd加倍 2,4,8,16。指数型增长
当然慢开始的cwnd的大小不是无限制增长的,当小于 ssthresh 时,使用慢启动算法,大于等于时则启动拥塞避免算法。 拥塞避免 : 那么进入拥塞避免算法后,它的规则是:每当收到一个 ACK 时,cwnd 增加 1/cwnd。 此时则变成了线性增长。
当报文
就这么一直增长着后,网络就会慢慢进入了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进行重传。
当触发了重传机制,也就进入了【拥塞发生算法】
拥塞发生
:
此时则采用两种方法解决丢包问题
超时重传:
当发生了「超时重传」,则就会使用拥塞发生算法。
这个时候,ssthresh 和 cwnd 的值会发生变化:
ssthresh
设为cwnd/2
,cwnd
重置为1
然后就重新慢启动,这大起大落不太行。
快速重传:
还有更好的方式,前面我们讲过「快速重传算法」。当接收方发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传。
TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,则 ssthresh 和 cwnd 变化如下:
cwnd = cwnd/2
,也就是设置为原来的一半; ssthresh = cwnd;
进入快速恢复算法
8.4 快速恢复 快速重传和快速恢复算法一般同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈。
正如前面所说,进入快速恢复之前,cwnd 和 ssthresh 已被更新了:
cwnd = cwnd/2 ,也就是设置为原来的一半;<br />ssthresh = cwnd;
然后,进入快速恢复算法如下:
拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了); 重传丢失的数据包; 如果再收到重复的 ACK,那么 cwnd 增加 1;
如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态;
具体细节大家可以看下这两篇文章
推荐阅读:
30张图解: TCP 重传、滑动窗口、流量控制、拥塞控制发愁
1.1 TCP的粘包和拆包
TCP是面向流,没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送 ,也有可能把多个小的包封装成一个大的数据包发送 ,这就是所谓的TCP粘包和拆包问题。
1.2 为什么会产生粘包和拆包呢?
要发送的数据小于TCP发送缓冲区的大小
,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包;接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包;要发送的数据大于TCP发送缓冲区剩余空间大小,
将会发生拆包;待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。即TCP报文长度-TCP头部长度>MSS。解决方案:发送端将每个数据包封装为固定长度在数据尾部增加特殊字符进行分割将数据分为两部分,一部分是头部,一部分是内容体;其中头部结构大小固定,且有一个字段声明内容体的大小。
MTU:一个网络包的最大长度
MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度;
推荐阅读:TCP粘包/拆包的产生原因和解决办法
握手
1.3三次握手是为了什么?
三次握手链接的本质是,所谓的建立连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结构来保证所谓的面向连接的特性。
三次握手是为了,保证可靠传输,我们假设客户端向A发送消息,首先告诉他,我要给你发消息啦,然后客户端给他发送,我收到你的消息啦,也就是Ack/syn。此条数据代表的含义为,我收到你的消息,同时我也准备好了,但是此时接受端,并不知道对方有没有收到消息,所以发送端,在收到接收端的ack和syn包之后,也要发送一个 ack 确认。这样双方则建立了链接。
三次握手过程
发送端:我发送syn(同步序列编号)的数据包给你啦。
接收端:我已经收到你的数据包啦,我将syn/ack编号发送给你啦
发送端:明白,我同时将ack的包发送给你啦。
握手情况如下
大家注意,这里三次握手时,客户端和服务端的状态也需要记忆,也是面试时的高频考点。
1.4 三次握手中,第二次握手的时候为什么还要传回SYN?
而回传SYN则是为了建立并确认从服务端到客户端的通信。是为了告诉发送端,我也准备好了。
1.5 为什么要三次握手,4次握手可以吗
三次握手才可以
阻止重复历史连接
的初始化(主要原因)三次握手才可以同步双方的初始序列号
三次握手才可以避免资源浪费
重复连接问题
因为网络会堵塞,所以有可能因为网络堵塞,第一个客户端发出第一个SYN = 10包之后,迟迟收不到SYN/ACK,所以就进行补发 SYN = 20,此时服务端收到了 SYN = 10 的旧包,然后发送ACK和SYN,但是呢?此时客户端发现我应该接收的是 SYN = 20 的ACK,而不是历史的连接,所以就会发送RST拒绝连接,等SYN= 20的 ACK来了之后,再进行连接。三次握手可以让客户端通过上下文来进行判断。
同步双方的初始序列号
序列号同步是可靠传输的基础,通过三次握手可以保证双方的序列号同步,其实四次握手也可以,只不过第二次握手把两个包合成一个了。
避免资源浪费
防止历史连接的建立,如果使用两次握手的话,现在已经连接成功,但是之前因为网络问题延迟传输的报文,再一次发到服务器则有可能再次造成连接。
TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。
不使用「两次握手」和「四次握手」的原因:
「两次握手」:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号; 「四次握手」:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。
推荐阅读:硬不硬你说了算!35 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
1.6 websocket
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)客户端可以与任意服务器通信。
(6)协议标识符是ws
(如果加密,则为wss
),服务器网址就是 URL。
推荐阅读:WebSocket 教程
挥手
1.7 四次挥手
A 和 B 打电话,通话即将结束后,A 说“我没啥要说的了”,B回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,这样通话才算结束。
1.8 为什么建立连接是三次握手,关闭连接确是四次挥手呢?
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。 而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次.
1.9 如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP设有一个活计时器,如果客户端没有发送请求,一直等待的话,则会白白浪费服务端请求,服务端每收到请求一次则会将活计时器重置,时间通常是设置为2小时,若2小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
UDP
1.10 UDP的特点
1.11 TCP和 UDP的区别
TCP 提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。 TCP 不提供广播或多播服务。由于 TCP 要提供可靠的,面向连接的传输服务(TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源),这一难以避免增加了许多开销,如确认,流量控制,计时器以及连接管理等。这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。TCP 一般用于文件传输、发送和接收邮件、远程登录等场景。
推荐阅读:TCP和UDP的最完整的区别
1.12 UDP的应用场景
广播:因为其可以一对多进行发送,所以可用于广播
实时游戏:因为TCP如果丢包,则会等待这个包进行重发,这样就会卡住,有可能出现,恢复后,人已经死了的情况。
网页或者app的访问,QUIC
音视频
2.应用层
HTTP
2.0 HTTP 状态码
状态码 | 类别 | 原因短语 |
---|---|---|
1XX | 信息性状态码 | 接收的请求正在处理 |
2XX | 成功状态码 | 请求正常处理完毕 |
3XX | 重定向状态码 | 需要进行附加操作以完成请求 |
4XX | 客户端错误状态码 | 服务端无法处理请求 |
5XX | 服务端错误状态码 | 服务端处理请求出错 |
301:永久重定向
302:临时重定向
400:语法错误
401:表示需要认证
403:表示请求被拒绝
404:没发现资源
500:服务器内部出现故障
503:服务器正在维护,或者已经超载
推荐阅读:HTTP 状态码
2.1 HTTP长连接和短链接
短链接:每进行一次HTTP通信,就要断开一次TCP连接
持久连接:建立一次TCP连接后进行多次请求和响应的交互。
Connection:keep-alive
推荐阅读:HTTP的长连接和短连接
2.2 GET 和 POST 请求方式对比
Http 常用的请求方法共有 8种,
- 在HTTP1.0中,定义了三种请求方法:
GET, POST 和 HEAD
方法。 - 在HTTP1.1中,新增了五种请求方法:
OPTIONS, PUT, DELETE, TRACE 和 CONNECT
方法 但我们常用的一般就是GET和POST
请求。
我们常用的主要有两种。
GET,POST他们两个的不同
GET有长度限制
POST 比GET安全,因为 url GET是直接暴露的。POST数据不会显示在URL中,是放在Request body中。
参数类型,GET只支持ASCLL码,POST没有要求。
GET请求会保存在浏览器记录里,POST浏览器也不会保存。
GET只支持url 编码,POST 则没有限制
GET会被浏览器主动缓存,POST则不会
GET回退是无害的,POST则是再次发出请求。
GET有没有Request Body 呢?
因为 GET是直接暴露在外面的,但是浏览器对url的大小限制为 2K,所以如果长度太大,也就是 url 参数较多,则有可能不被接收。
有人说POST 比 GET安全,这是因为 POST 在地址栏,url是看不到的其实在http 中,他们两个都是不安全的,因为 HTTP 是明文传输。
GET 和 POST 请求发送的数据包有什么不同?
GET是一个包将Header 和 body 同时发送过去,POST 是先发送head ,再发送body,分两个包发送。
就像是GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼老铁,我等下要送一批货来,你们准备接收一下哈
,然后再回头把货送过去。
推荐阅读:GET 和 POST 到底有什么区别?
2.3 HTTP 1.1
HTTP1.0和HTTP1.1的一些区别
HTTP1.0最早在网页中使用是在1996年,那个时候只是使用一些较为简单的网页上和网络请求上,而HTTP1.1则在1999年才开始广泛应用于现在的各大浏览器网络请求中,同时HTTP1.1也是当前使用最为广泛的HTTP协议。 主要区别主要体现在:
缓存处理
,
在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。带宽优化及网络连接的使用,错误通知的管理
,
在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。长连接
,
HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。压缩报文
Host头处理
,
在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
HTTP 2.0
二进制编码
:HTTP/2 厉害的地方在于将 HTTP/1 的文本格式改成二进制格式传输数据,极大提高了 HTTP 传输效率,而且二进制数据使用位运算能高效解析,这里一句话总结就是,将侦使用二进制格式传输。 header压缩
:
HTTP/2 没使用常见的 gzip 压缩方式来压缩头部,而是开发了 HPACK 算法,HPACK 算法主要包含三个组成部分:
静态字典;
动态字典;
Huffman 编码(压缩算法)
客户端和服务器两端都会建立和维护「字典 」,用长度较小的索引号表示重复的字符串,再用 Huffman 编码压缩数据,可达到 50%~90% 的高压缩率 。静态表是保存在 http2框架里的。
多路复用分侦
(server push):HTTP 2.0 其实是将三个请求变成三个流,将数据分成帧,乱序发送到一个 TCP 连接中。将一个请求变成一个流,然后再将流拆分成侦,然后这些侦是可以混杂在一起进行发送。
服务端主动发送:
可以在用户请求 html 时,可以主动的推送 css 资源,一次请求,多次发送。
推荐阅读:
2.4 http3.0 QUIC和之前的不同
http多是基于 TCP 的传输,因为 HTTP 2.0 也是基于 TCP 协议的,TCP 协议在处理包时是有严格顺序的。当其中一个数据包遇到问题,TCP 连接需要等待这个包完成重传之后才能继续进行。虽然 HTTP 2.0 通过多个 stream,使得逻辑上一个 TCP 连接上的并行内容,进行多路数据的传输,然而这中间并没有关联的数据。一前一后,前面 stream 2 的帧没有收到,后面 stream 1 的帧也会因此阻塞。
基于 UDP 自定义的类似 TCP 的连接:
一条 TCP 连接是由四元组标识的,分别是源 IP、源端口、目的 IP、目的端口。ip改变之后连接断开
QUIC 自己的逻辑里面维护连接的机制,不再以四元组标识,而是以一个 64 位的随机数作为 ID 来标识,而且 UDP 是无连接的,所以当 IP 或者端口变化的时候,只要 ID 不变,就不需要重新建立连接。
重发:
tcp的重发是有缺陷的,当我们如果一个包,由于网络堵塞,发送失败,进行重传之后,然后我们收到包之后,不知道应该如何计算往返时间,不利于我们拥塞控制。
这里加入了,偏移量和id,重发之后加1即可。
多路复用:
有了自定义的连接和重传机制,我们就可以解决上面 HTTP 2.0 的多路复用问题。同 HTTP 2.0 一样,同一条 QUIC 连接上可以创建多个 stream,来发送多个 HTTP 请求。但是,QUIC 是基于 UDP 的,一个连接上的多个 stream 之间没有依赖。这样,假如 stream2 丢了一个 UDP 包,后面跟着 stream3 的一个 UDP 包,虽然 stream2 的那个包需要重传,但是 stream3 的包无需等待,就可以发给用户。
流量控制技术
在 TCP 协议中,接收端的窗口的起始点是下一个要接收并且 ACK 的包,即便后来的包都到了,放在缓存里面,窗口也不能右移,因为 TCP 的 ACK 机制是基于序列号的累计应答,一旦 ACK 了一个序列号,就说明前面的都到了,所以只要前面的没到,后面的到了也不能 ACK,就会导致后面的到了,也有可能超时重传,浪费带宽。
只要收到的,就进行确认,因为后面的到了,前面的肯定已经发送,所以我们可以移动窗口,等待确认前面的和重发即可。
推荐阅读:科普:QUIC协议原理分析
2.5 HTTP的缺点
明文传输
没有校验,有可能被篡改
没有验证通信方身份
HTTPS采用混合加密机制,位于HTTP/TCP之间,主要为高层协议服务。
2.6 HTTP请求过程
在浏览器输入网址显示页面的过程
1.查询浏览器缓存,如果有直接访问
2.查询本地host文件,查询本地缓存,或者使用cmd,使用ipconfig /displaydns 命令查询
3.向DNS服务器发送DNS请求,查询本地DNS服务器(此时用到的是递归查询),这其中用的是UDP的协议
4.本地域名服务器会向根域名服务器发送一个请求
,如果根域名服务器也不存在该域名时,
5.本地域名会向顶级域名服务器的下一级DNS服务器发送一个请求,依次类推下去。直到最后本地域名服务器得到google的IP地址并把它缓存到本地,供下次查询使用。(上诉的迭代方式是迭代查询)
6.此时我们已经知道了ip地址,及其默认的端口号,http默认的是80端口,https默认的是https端口
7.我们首先会尝试使用http建立socket连接,三次握手之后,开始传送数据,如果是http的话,那么则接收数据,如果不是http,是https则会返回 3开头的重定向,将端口号从 80 端口改成 443 端口,并四次挥手断开之前的连接。
8.再来一遍三次握手,此时还会采用SSL的加密技术来保证传输数据的安全性,保证数据传输过程中不被修改或者替换之类的
9.沟通好双方使用的认证算法,加密和检验算法,在此过程中也会检验对方的CA安全证书。
10.连接完毕,开始传输数据
这里还有很多细节,比如通过ip地址和子网掩码判断是否在同一子网,报文每一跳的情况等。还有 DNS 解析时,递归查询和迭代查询使用哪个传输层协议等,答的尽量细一些。
推荐阅读:HTTP请求的完全过程
2.7 聊聊HTTPS
HTTPS 是以安全为目标的 HTTP 通道.
在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 。HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。
HTTPS使用的是443端口,HTTP是80端口,HTTPS比HTTP多了四次握手的过程所以效率有所降低,大概只有HTTP的1/10。HTTPS则是为了来解决HTTP明文传输,没有检验,有可能被篡改,无法验证对方身份的情况。
HTTPS原理也会考察,而且是高频考点,大家可以看下下面这两个文章
推荐阅读:
3.网络层
3.0 通过IP发送请求的过程
TCP 层发送每一个报文的时候,都需要加上自己的地址(即源地址)和它想要去的地方(即目标地址)。
将这两个信息放到 IP 头里面,交给 IP 层进行传输。IP 层需要查看目标地址和自己是否是在同一个局域网。如果是,就发送 ARP 协议来请求这个目标地址对应的 MAC 地址,然后将源 MAC 和目标 MAC 放入 MAC 头,发送出去即可;如果不在同一个局域网,就需要发送到网关,还要需要发送 ARP 协议,来获取网关的 MAC 地址,然后将源 MAC 和网关 MAC 放入 MAC 头,发送出去。网关收到包发现 MAC 符合,取出目标 IP 地址,根据路由协议找到下一跳的路由器,获取下一跳路由器的 MAC 地址,将包发给下一跳路由器。
推荐阅读:图解 | 你管这破玩意叫网络?
3.1 有了IP地址,为什么还要用MAC地址?
简而言之,标识网络中的一台计算机,比较常用的就是IP地址和MAC地址 ,但计算机的IP地址可由用户自行更改,管理起来就相对困难,而MAC地址不可更改,所以一般会把IP地址和MAC地址组合起来使用。
那只使用MAC地址不用IP地址行不行呢?不行的!因为最早就是MAC地址先出现的,并且当时并不用IP地址,只用MAC地址,后来随着网络中的设备越来越多,整个路由过程越来越复杂,便出现了子网的概念。对于目的地址在其他子网的数据包,路由只需要将数据包送到那个子网即可。
那为什么要用IP地址呢?是因为IP地址是和地域相关的,对于同一个子网上的设备,IP地址的前缀都是一样的,这样路由器通过IP地址的前缀就知道设备在在哪个子网上了,而只用MAC地址的话,路由器则需要记住每个MAC地址在哪个子网,这需要路由器有极大的存储空间,是无法实现的。
IP地址可以比作为地址,MAC地址为收件人,在一次通信过程中,两者是缺一不可的。
推荐阅读: 有了 IP 地址,为什么还要用 MAC 地址?
4.网络安全篇
4.0 什么是XSS攻击
它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意攻击用户的特殊目的。
XSS的攻击方式就是想办法“教唆”用户的浏览器去执行一些这个网页中原本不存在的前端代码。
其实我们常用的留言板就可以产生XSS攻击,我们知道留言板通常的任务就是把用户留言的内容展示出来。
正常情况下,用户的留言都是正常的语言文字,留言板显示的内容也就没毛病。然而这个时候如果有人不按套路出牌,在留言内容中丢进去一行
<script>alert(“这是一个攻击”)</script>
那么留言板界面的网页代码就会变成形如以下:
那么这个时候问题就来了,当浏览器解析到用户输入的代码那一行时会发生什么呢?答案很显然,浏览器并不知道这些代码改变了原本程序的意图,会照做弹出一个信息框。就像这样
<html>
<head>
<title>留言板</title>
</head>
<body>
<div id=”board”
<script>alert(“这是一个攻击”)</script>
</div>
</body>
</html>
4.1 如何解决xss攻击
1.不相信用户输入
2.限制输长度
3.html转义等
4.对跳转型链接进行特殊对待
推荐阅读:浅谈XSS攻击的那些事(附常用绕过姿势)
4.2 半连接队列和 SYN Flood 攻击的关系
TCP进入三次握手前,服务端会从CLOSED 状态变为LISTEN 状态,同时在内部创建了两个队列:半连接队列(SYN队列)和全连接队列(ACCEPT队列)。
什么是半连接队列(SYN队列) 呢? 什么是全连接队列(ACCEPT队列) 呢?回忆下TCP三次握手的图:
TCP三次握手时,客户端发送SYN到服务端,服务端收到之后,便回复ACK和SYN ,状态由LISTEN变为SYN_RCVD ,此时这个连接就被推入了SYN队列 ,即半连接队列。
当客户端回复ACK, 服务端接收后,三次握手就完成了。这时连接会等待被具体的应用取走,在被取走之前,它被推入ACCEPT队列,即全连接队列。
SYN Flood是一种典型的DoS (Denial of Service,拒绝服务) 攻击,它在短时间内,伪造不存在的IP地址 ,向服务器大量发起SYN报文。当服务器回复SYN+ACK报文后,不会收到ACK回应报文,导致服务器上建立大量的半连接半连接队列满了,这就无法处理正常的TCP请求啦。
主要有 syn cookie 和SYN Proxy防火墙 等方案应对。
- syn cookie :在收到SYN包后,服务器根据一定的方法,以数据包的源地址、端口等信息为参数计算出一个cookie值作为自己的SYNACK包的序列号,回复SYN+ACK后,服务器并不立即分配资源进行处理,等收到发送方的ACK包后,重新根据数据包的源地址、端口计算该包中的确认序列号是否正确,如果正确则建立连接,否则丢弃该包。
- SYN Proxy防火墙 :服务器防火墙会对收到的每一个SYN报文进行代理和回应,并保持半连接。等发送方将ACK包返回后,再重新构造SYN包发到服务器,建立真正的TCP连接。
推荐阅读:半连接队列、全连接队列、SYN Flood 攻击、如何应对SYN Food攻击、半连接队列和 SYN Flood 攻击的关系
4.3 socket的执行过程
在connect位置进行三次握手
IO多路复用发生在accept函数之后
监听的是已经建立好连接准备发送数据的socket
说 TCP 的 Socket 就是一个文件流,是非常准确的。因为,Socket 在 Linux 中就是以文件的形式存在的。
除此之外,还存在文件描述符。写入和读出,也是通过文件描述符。
socket是一个文件,那么就有文件描述符
该图片来自于《极客时间》
socket对应的文件不是存在磁盘中的,是存在内存中的,方便快速传输。
服务端一般是listen一个端口,然后理论上的最大连接数,则和客户端ip地址的数目和端口号的数目有关,则是 2^32 * 2^16次方。
但是现实中不能够连接那么多,因为socket文件是存储在内存中的,内存限制,而是文件描述符的个数也有所限制。
我们如何建立更多的socket 连接,我们可以通过fork子进程的方式,父进程用来
进程复制过程
该图片来自于《极客时间》
通过fork函数创建的子进程和父进程几乎是一模一样的,(文件描述符列表也复制了一份,这样子进程就能通过这个一模一样的文件描述符去操作父进程的已连接socket了。
epoll create
epoll controll:挂到红黑树上时,如何快速放到链表,当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。
所以,当一个socket上有数据到了,内核在把网卡上的数据copy到内核中后就来把socket插入到准备就绪链表里了
epoll wait 查看链表
推荐阅读:socket编程到底是什么?