计算机网络
HTTP
HTTP的报文结构
HTTP请求种类
- get:获取资源(多媒体,程序执行结果)
- post:传输实体主体,相比于
get
传输,post
请求的数据会放置在内容实体中而不是uri(Universal Resource Identifier)
之后,安全性大大增强 - put:传输文件,由于
http1.1
本身不自带验证机制,所以安全性欠佳。一般web
不使用此方法 - head:获得报文首部,与
get
一样,只是不获取报文主体,用来验证uri
的有效性 - delete:删除文件 类似
put
- options:询问支持的方法
- trace:追踪路径,让
web
服务器端将之前的请求通信环回给客户端,用来确认连接过程中,代理中转的加工/篡改。 - connect:要求用隧道协议连接代理,主要使用
ssl
和tsl
把通信内容加密后经网络隧道传输
HTTP状态码
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:
1信息通知,2成功,3暂时没成功,但可以重定向,45是失败,4是客户端错误,5是服务器错误
分类 | 分类描述 |
---|---|
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
HTTP状态码列表:
状态码 | 状态码英文名称 | 中文描述 |
---|---|---|
100 | Continue | 继续。客户端应继续其请求 |
101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
200 | OK | 请求成功。一般用于GET与POST请求 |
201 | Created | 已创建。成功请求并创建了新的资源 |
202 | Accepted | 已接受。已经接受请求,但未处理完成 |
203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
206 | Partial Content | 部分内容。服务器成功处理了部分GET请求 |
300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
303 | See Other | 查看其它地址。与301类似。使用GET和POST请求查看 |
304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问 |
306 | Unused | 已经被废弃的HTTP状态码 |
307 | Temporary Redirect | 临时重定向。与302类似。使用GET请求重定向 |
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
402 | Payment Required | 保留,将来使用 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置”您所请求的资源无法找到”的个性页面 |
405 | Method Not Allowed | 客户端请求中的方法被禁止 |
406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求 |
407 | Proxy Authentication Required | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时 |
409 | Conflict | 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突 |
410 | Gone | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
411 | Length Required | 服务器无法处理客户端发送的不带Content-Length的请求信息 |
412 | Precondition Failed | 客户端请求信息的先决条件错误 |
413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
414 | Request-URI Too Large | 请求的URI过长(URI通常为网址),服务器无法处理 |
415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式 |
416 | Requested range not satisfiable | 客户端请求的范围无效 |
417 | Expectation Failed | 服务器无法满足Expect的请求头信息 |
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
501 | Not Implemented | 服务器不支持请求的功能,无法完成请求 |
502 | Bad Gateway | 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 |
503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求 |
505 | HTTP Version not supported | 服务器不支持请求的HTTP协议的版本,无法完成处理 |
HTTP的首部字段
通用字段:在请求头和响应头里都可以出现;
请求字段:仅能出现在请求头里,进一步说明请求信息或者额外的附加条件;
响应字段:仅能出现在响应头里,补充说明响应报文的信息;
实体字段:它实际上属于通用字段,但专门描述 body 的额外信息。
首部字段:缓存
Cache-Control:
max-age:资源存储的最长时间
no-store:不允许缓存
no-cache:可以缓存,使用之前必须要去服务器验证是否过期
must-revalidate:资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求
条件缓存
if-Modified-Since:指的是文件最后修改时间。在给定的日期时间之后,如果请求的资源没有改变,就返回304响应;如果有改变,返回资源
If-None-Match:对于 GET 和 HEAD请求方法来说,当且仅当服务器上没有任何资源的 ETag 属性值与这个首部中列出的相匹配的时候,服务器端会才返回所请求的资源,响应码为 200
HTTPS的通信过程⭐
HTTPS
是一种通过计算机网络进行安全通信的传输协议。HTTPS
经由 HTTP
进行通信,但利用 SSL/TLS 来加密数据包。 HTTPS
的通信过程,充分利用了各种加密算法及其特性。HTTPS
只是在原有的协议接口替换成了**SSL(Secure Socket Layer)和TLS(Transport Layer Security)**协议
客户端或者浏览器向服务器发送
https
请求服务器将数字证书(公钥+数字签名)返回给客户端
浏览器接收到服务器公钥
浏览器收到公钥后会对公钥进行一系列的验证,如:颁发机构,过期时间等等。认证失败会有警告,成功的话,会生成一个随机的对称密钥作为对称加密的密钥,用服务器返回的公钥对这个随机密钥进行加密
加密后的随机密钥发送到服务器
服务器收到公钥加密后的随机密钥,会拿自己的私钥去解,解开之后得到随机密钥
客户端与服务器进行加密通信
客户端和服务器端信息数据通信,以这个随机密钥进行对称加密。
总结:S发公钥给C,C验证后用公钥加密随机秘钥再发给S,S用私钥解密得到随机秘钥,最后双方用随机秘钥通信。
非对称加密算法+对称加密算法
HTTPS 采用的是对称加密和非对称加密结合的「混合加密」方式:
- 在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
- 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。
非对称加密算法,它有两个密钥:一个是公钥,可以明文传输的。一个是私钥,由发送方保存,其它人都不知道。非对称加密算法的加密和解密算法不同。通过公钥加密的信息只有用私钥才能解开。
主要是由于非对称加密算法运算量大,用非对称加密算法进行通信,其加解密过程特别慢。因此可以第一次用非对称加密算法传递对称加密算法的密钥,后续通信就用对称加密算法。除了第一次用非对称加密算法加解密密钥的时候比较慢外,其它时间都不会慢了。而且也可以保证对称加密算法密钥的安全性。这样可以充分利用非对称加密算法和对称加密算法的各自特点。
数字证书—防止中间人攻击
为了防止在通信过程中有中间人截获两端的非对称密钥,导致两端收到的公钥都是中间人的,可以获取两端的信息然后中转。找个可靠的人做公证人,两端各自把公钥交给他。由他颁布一个证书,证书包含公钥以及两端的身份信息,来证明两端各自的身份。但是这个证书也可以在传递过程中被篡改。
数字摘要算法
摘要算法用来实现完整性,能够为数据生成独一无二的「指纹」,用于校验数据的完整性,解决了篡改的风险。
为了解决数字证书中中间人攻击的问题,可以让公证人用数字摘要算法,把公钥和身份信息生成一个摘要。同时用非对称加密算法对摘要进行加密,生成数字签名。然后把【公钥和身份信息+数字签名】合并,形成数字证书。在获得数字证书的时候,就可以用公钥进行解密生成摘要信息,再用数字摘要算法对公钥和身份信息生成摘要信息,两者比对,如果能匹配,就说明没有被篡改 。
数字证书通常来说是由受信任的数字证书颁发机构CA,在验证服务器身份后颁发。
证书内置
为了防止公证人公钥传输过程也会出现中间人攻击问题,可以把公证人公钥预先加载在操作系统中。微软等公司会根据一些权威安全机构的评估选取一些信誉很好并且通过一定的安全认证的证书发布机构,把这些证书发布机构的证书默认安装在操作系统中,并且设置为操作系统信任的数字证书。
get/post 区别
GET
用于信息获取,不会增删改服务器上的内容;POST
请求可能修改服务器上资源;GET
请求数据附在URL
后面,而POST
在HTTP
包体内;GET
方法产生一个TCP数据包,把首部和数据一起发送;POST
方法产生两个TCP数据包,先发首部,服务器响应后再发数据
http/https 0.9、1.0、1.1、2.0、3.0的特点和区别
Http0.9
- 请求方法支持有限
只支持GET
请求方式,不支持其他请求方式,因此客户端向服务端传输信息的量非常有限,也就是现在常用的Post
请求无法使用 - 不支持请求头header
不能在请求中指定版本号,服务端只具有返回HTML
字符串的能力 - 响应即关闭
服务端相响应之后,立即关闭TCP
连接
Http1.0
1.0版本主要是对0.9版本的强化,效果也比较明显,主要特性和缺点包括:
- 丰富请求方法
请求方式新增了POST
,DELETE
,PUT
,HEADER
等方式,提高了客户端向服务端发送信息的量级 - 增加请求头和响应头
增添了请求头和响应头的概念,可以在通信中指定了HTTP
协议版本号,以及其他header
信息,使得C/S交互更加灵活方便 - 丰富数据传输内容
扩充了传输内容格式包括:图片、音视频资源、二进制等都可以进行传输,相比0.9的只能传输html
内容让http
的应用场景更多。
缺点如下:
- 链接复用性差
1.0版本中每个TCP连接只能发送一个请求,数据发送完毕连接就关闭,如果还要请求其他资源,就必须重新建立连接。TCP为了保证正确性和可靠性需要客户端和服务器三次握手和四次挥手,因此建立连接成本很高,基于拥塞控制开始时发送速率较慢,所以1.0版本的性能并不理想。 - 无状态无连接的弊端
1.0版本是无状态且无连接的,换句话说就是服务器不跟踪不记录请求过的状态,客户端每次请求都需要建立tcp连接不能复用,并且1.0规定在前一个请求响应到达之后下一个请求才能发送,如果前一个阻塞后面的请求就会被阻塞。 丢包和乱序问题和高成本的链接过程让复用和队头阻塞产生很多问题,所以无连接无状态是1.0版本的一个弱肋。
Http1.1
1.1版本在1.0版本发布后大约1年就推出了,是对1.0版本的优化和完善,1.1版本的主要特点包括:
- 增加长连接
新增Connection
字段,可以设置keep-alive
值保持连接不断开,即TCP
连接默认不关闭,可以被多个请求复用,这也是1.1版本很重要的优化,在请求首部字段中提出keepalive之后,只要任意一段没有明确提出断开连接,tcp就一直会保持连接状态。但是在S端服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着,仍然存在队头阻塞问题。 - 管道化
在长连接的基础上,管道化可以不等第一个请求响应继续发送后面的请求,但响应的顺序还是按照请求的顺序返回,即在同一个TCP连接中,客户端可以同时发送多个请求,进一步改进了HTTP协议的传输效率。 - 更多的请求方法
增加了PUT
、PATCH
、OPTIONS
、DELETE
等请求方式。 - host字段
Host
字段用来指定服务器的域名,这样就可以将多种请求发往同一台服务器上的不同网站,提高了机器的复用,这个也是重要的优化
缺点:
- 仍然存在着队首阻塞的问题。也就是虽然请求可以同时发送了,但是要是前面的回应特别慢,后面就会有许多请求排队等着,仍然存在队头阻塞问题。
Http2.0
HTTP2.0多路复用+TLS安全加密+TCP拥塞控制
2.0版本是个里程碑式的版本,相比1.x版本有了非常多的优化去适应当前的网络场景,其中几个重要功能点包括:
二进制格式
1.x
是文本协议,然而2.0是以二进制帧为基本单位,可以说是一个二进制协议,将所有传输的信息分割为消息和帧,并采用二进制格式的编码,一帧中包含数据和标识符,使得网络传输变得高效而灵活。二进制分帧层binary framing layer在不修改请求方法和语义的基础上,重新设计了编码机制。二进制编码机制使得通信可以在单个TCP连接上进行,该连接在整个对话期间一直处于活跃状态。
- 链接Link
就是指一条C/S之间的TCP链接,这是个基础的链路数据的高速公路 - 数据流Stream
已建立的TCP连接内的双向字节流,TCP链接中可以承载一条或多条消息 - 消息Message
消息属于一个数据流,消息就是逻辑请求或响应消息对应的完整的一系列帧,也就是帧组成了消息 - 帧Frame
帧是通信的最小单位,每个帧都包含帧头和消息体,标识出当前帧所属的数据流
- 链接Link
多路复用
这是一个非常重要的改进,1.x中建立多个连接的消耗以及效率都存在问题,2.0版本的多路复用多个请求共用一个连接,多个请求可以同时在一个TCP连接上并发,主要借助于二进制帧中的标识进行区分实现链路的复用。客户端和服务器将交互数据分解为相互独立的帧,互不影响地交错传输,最后再在对端根据帧头中的流标识符把它们重新组装起来,从而实现了TCP链接的多路复用。
头部压缩
2.0版本使用使用HPACK算法对头部header
数据进行压缩,从而减少请求的大小提高效率,这个非常好理解,之前每次发送都要带相同的header
,显得很冗余,2.0
版本对头部信息进行增量更新有效减少了头部数据的传输。2.0版本中HPACK算法在C/S中使用首部表来存储之前发送的键值对,对于相同的数据通信期间几乎不会改变的通用键值对只需发送一次即可。
极端情况如果请求头每次没有变化,那么传输中则不包含首部,也就是首部开销就是零字节。如果首部键值对发生变化了,也只需要发送变化的数据,并且将新增或修改的首部帧会被追加到首部表,首部表在链接存活期始终存在, 并且由客户端和服务器共同更新和维护。
简单说就是客户端和服务端共同维护了一个key-value的结构,发生变化时则更新传输,否则就不传输,这样相当于首次全量传输之后增量更新传输即可,这个思想在日常开发中也非常普遍,不用想的太复杂。
服务端推送
这个功能有点意思,之前1.x
版本服务端都是收到请求后被动执行,在2.0版本允许服务器主动向客户端发送资源,这样在客户端可以起到加速的作用。- 在实际的C/S交互中这种主动推送额外资源的方法很有效,因为几乎每个网络应用都会包含多种资源,客户端需要全部逐个获取它们,此时如果让服务器提前推送这些资源,从而可以有效减少额外的延迟时间,因为服务器可以知道客户端下一步要请求什么资源。
HTTP2.0存在的不足(主要是TCP的问题)
- 建立连接时间长
- 队头阻塞问题(HTTP2.0协议的多路复用机制解决了HTTP层的队头阻塞问题,但是在TCP层仍然存在队头阻塞问题。TCP协议在收到数据包之后,这部分数据可能是乱序到达的,但是TCP必须将所有数据收集排序整合后给上层使用,如果其中某个包丢失了,就必须等待重传,从而出现某个丢包数据阻塞整个连接的数据使用。)
- 移动互联网领域表现不佳(弱网环境)
Http3.0
HTTP3.0又称为HTTP Over QUIC,其弃用TCP协议,改为使用基于UDP协议的QUIC协议来实现。
- QUIC协议(Quick UDP Internet Connections)
QUIC提高了当前正在使用TCP的面向连接的Web应用程序的性能。它在两个端点之间使用用户数据报协议(UDP)建立多个复用连接来实现此目的。
QUIC的次要目标包括减少连接和传输延迟,在每个方向进行带宽估计以避免拥塞。它还将拥塞控制算法移动到用户空间,而不是内核空间,此外使用前向纠错(FEC)进行扩展,以在出现错误时进一步提高性能。
- 基于TCP协议和TLS协议的HTTP2.0在真正发送数据包之前需要花费一些时间来完成握手和加密协商,完成之后才可以真正传输业务数据。但是QUIC则第一个数据包就可以发业务数据,从而在连接延时有很大优势,可以节约数百毫秒的时间。
- 使用QUIC协议的客户端和服务端要使用1RTT进行密钥交换,使用的交换算法是DH(Diffie-Hellman)迪菲-赫尔曼算法。首次连接之后传递了config包,里面包含了服务端公钥和两个随机数,客户端会将config存储下来,后续再连接时可以直接使用,从而跳过这个1RTT,实现0RTT的业务数据交互。
- QUIC协议基于UDP实现摒弃了五元组(SIP+SPort+DIP+DPort+协议号)的概念,使用64位的随机数作为连接的ID,并使用该ID表示连接。基于QUIC协议之下,我们在日常wifi和4G切换时,或者不同基站之间切换都不会重连,从而提高业务层的体验。
- QUIC协议的核心思想是将TCP协议在内核实现的诸如可靠传输、流量控制、拥塞控制等功能转移到用户态来实现,同时在加密传输方向的尝试也推动了TLS1.3的发展。
HTTP的无状态性
http
是一种无状态协议,即不会保存请求和响应之间的通信状态。好处是可以加快处理速度,确保协议的可伸缩性。http
最初的设计是无状态的(stateless),但是无状态的 http
无法满足互联网日益发展的需求,于是业界扩展了 http
协议,增加了有状态(stateful)协议头,使之变成一个有状态协议。
两种用于保持HTTP连接状态的技术就应运而生了,一个是Cookie,而另一个则是Session。HTTP本身是一个无状态的连接协议,为了支持客户端与服务器之间的交互,我们就需要通过不同的技术为交互存储状态,而这些不同的技术就是Cookie和Session了。
Cookie
由于HTTP是一种无状态的协议,服务器单纯从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用 response
向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
Cookie具有不可跨域名性
很多网站都会使用Cookie。例如,Google会向客户端颁发Cookie,Baidu也会向客户端颁发Cookie。那浏览器访问Google会不会也携带上Baidu颁发的Cookie呢?或者Google能不能修改Baidu颁发的Cookie呢?
答案是否定的。Cookie具有不可跨域名性。根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。
Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作Google的Cookie而不会操作Baidu的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。Google与Baidu的域名不一样,因此Google不能操作Baidu的Cookie。
Session
由于网页是一种无状态的连接程序,因此无法得知用户的浏览状态。在网上购物的时,把很多商品加入了购物车,而在结账时网站却不知道你购物车有哪些物品。为了解决这个问题,服务器端就为特定用户创建了特定的session
,用于标示并跟踪这个用户,这样才知道购物车里有哪些商品。
Session
是另一种记录客户状态的机制,不同的是Cookie
保存在客户端浏览器中,而Session
保存在服务器上。- 客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是
Session
。客户端浏览器再次访问时只需要从该Session
中查找该客户的状态就可以了。 - 如果说
Cookie
机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session
机制就是通过检查服务器上的“客户明细表”来确认客户身份。 Session
相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。
Session和Cookie的关系
cookie
是一个实际存在的、具体的东西,http
协议中定义在header
中的字段。session
是一个抽象概念、开发者为了实现中断和继续等操作,将client
和server
之间一对一的交互,抽象为“会话”,进而衍生出“会话状态”,也就是session
的概念。- 即
session
描述的是一种通讯会话机制,而cookie
只是目前实现这种机制的主流方案里面的一个参与者,它一般是用于保存session ID。
更多介绍
从浏览器输入URL到出现页面经过了哪些阶段
输入网址
URL的形式: schema://host:port/path?query#fragment
-schema
: 协议,例如 http
, https
, ftp
等
-host
: 域名或者 ip
地址
-port
: 端口,http
默认端口 80
,可以省略
-path
: 路径,例如 /abc
/a/b/c
-query
: 查询参数,例如 token=sdfs2223fds2&name=sdffaf
-fragment
: 锚点(哈希 Hash
),用于定位页面的某个位置。
符合规则的URL
http://www.baidu.com/java/web?flag=1#function
缓存解析
浏览器获取了这个 url
,它先去缓存当中看看有没有,依次从浏览器缓存->系统缓存->路由器缓存当中查看,如果有从缓存当中显示页面,这样是不需要发送 http
请求的。如果没有那就进行步骤3。
缓存就是把之前访问的web资源,比如一些js,css,图片什么的保存在本机的内存或者磁盘当中。
域名DNS解析
当缓存中没有这个 url
的时候,就需要发送 http
请求了,那么在发送 http
请求之前,需要先进行DNS解析将域名解析成 ip
地址。DNS解析存在着多级缓存:
- 浏览器缓存、系统缓存(hosts)、路由器缓存
- 本地DNS服务器(ISP提供)
- 有映射,解析完成
- 有缓存,解析完成,不权威
- 上述都失败
- 未采用转发模式(迭代):
- 发给根DNS服务器
- 返回负责该顶级域名服务器的IP (如.com)
- 向该顶级域名服务器IP发送请求
- 如果失败,找下一级DNS服务器(如qq.com)
- 循环往复,直到得到结果,发给本地DNS服务器,再发给客户机
- 采用转发模式(递归):
- 请求转发至上一级DNS服务器
- 不断重复
- 递归查询:本机向本地域名服务器发出一次查询请求,就静待最终的结果。如果本地域名服务器无法解析,自己会以
DNS
客户机的身份向其它域名服务器查询,直到得到最终的IP
地址告诉本机 - 迭代查询:本地域名服务器向根域名服务器查询,根域名服务器告诉它下一步到哪里去查询,然后它再去查,每次它都是以客户机的身份去各个服务器查询。
- 未采用转发模式(迭代):
DNS优化
- DNS缓存
DNS存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。 - DNS负载均衡
DNS可以返回一个合适的机器的 IP 给用户,例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等。
tcp链接,三次握手
在域名解析之后,浏览器向服务器发起了http请求,tcp连接,三次握手建立tcp连接。TCP协议是面向连接的,所以在传输数据前必须建立连接。
(1)客户端向服务器发送连接请求报文;
(2)服务器端接受客户端发送的连接请求后后回复ACK报文,并为这次连接分配资源。
(3)客户端接收到ACK报文后也向服务器端发生ACK报文,并分配资源。
这样TCP连接就建立了。
在此之后,浏览器开始向服务器发送http请求,请求数据包。请求信息包含一个请求头部和一个请求体。
服务器收到请求
服务器收到浏览器发送的请求信息,返回一个响应头和一个响应体。
浏览器页面渲染
- 处理HTML标记并构建DOM树;
- 处理CSS标记并构建CSSOM树;
- 将DOM和CSSOM合并为一颗渲染树,通常为了更好的用户体验,渲染会与解析同时进行,将已经解析好的树渲染出来。
- 根据渲染树来布局,以计算每个节点的几何信息(重排)
- 将各个结点绘制到屏幕上(重绘)
- 如果 DOM 或 CSSOM 被修改,以上过程需要重复执行,这样才能计算出哪些像素需要在屏幕上进行重新渲染。
断开连接,四次挥手
TCP/UDP/运输层
UDP和TCP的差别⭐
UDP:
- 无连接:减少了开销和发送前时延;
- 尽最大努力交付:不保证可靠交付;
- 面向报文:对应用层交下来的报文既不合并,也不拆分,保留这些报文的边界。
- 没有拥塞控制:网络拥塞不会使源主机发送速率降低,允许在网络拥塞时丢失一些数据,却不允许数据有太大的时延。
- 支持一对一、一对多、多对一、多对多的交互通信
- 首部开销小: 首部长度只有 8 字节,比 TCP 的 20 字节短。
TCP:
- 面向连接: 传输前需建立连接,传输完成需释放连接;TCP 连接是一条逻辑连接。
- 提供可靠交付: 无差错、不丢失、不重复、不失序;
- 面向字节流: TCP 把应用进程交下来的数据看作一连串的无结构字节流;
- 有拥塞控制
- 点对点: 每一条 TCP 连接只能有两个端点;
- 首部开销大:20字节
TCP/UDP数据发送和接收过程
发送端
数据发送是发送到物理链路层的,从应用层开始,经过一层层的数据报文的封装,最终封装成以太网封装格式 和 802.x 封装格式的数据包,通过有线网络或无线网络在以太网上传输数据帧(bit流)。
接收端
接收端和发送端的顺序刚好相反。即分别经过
- 经过数据链路层去掉以太网的头部得到以太网MAC帧
- 经过网络层去掉IP的头部得到IP数据包
- 经过传输层去掉
TCP/UDP
的头部得到报文段/用户数据报 - 经过应用层得到数据流
就完成了整个的数据传输过程。
复用与分用
应用层所有应用进程都可以通过运输层传输到 IP
层,称为复用;运输层从 IP
层收到发送给各应用进程的数据后,必须分别交付给指明的各应用进程,称为分用。
TCP协议的可靠性体现在哪里
- 应用数据被分割成TCP认为最适合发送的数据块。(这和UDP完全不同,应用程序产生的数据报长度将保持不变)。
- 超时重传: 当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
- 有序编号:TCP给发送的每一一个包进行编号 ,接收方对数据包进行排序,把有序数据传送给应用层。(TCP报文段作为IP数据报来传输,IP数据报的大刀可能会失序,因此TCP报文段的到达也可能会失序,如果必要,TCP将对收到的数据进行重新排序)。
- 校验和: TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错, TCP将丢弃这个报文段和不确认收到此报文段。
- IP数据报会发生重复,TCP的接收端会丢弃重复的数据。
- 流量控制: TCP连接的每一方都有固定大小的缓冲空间 , TCP的接收端只允许发送端发送接收端缓冲区能接纳的我数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP使用的流量控制协议是可变大小的滑动窗口协议。
- 拥塞控制:当网络拥塞时,减少数据的发送。
- 确认响应:对于一个收到的请求,将发送一个确认。这个确认通常要延迟几分之一秒。
TCP协议保证数据传输可靠性的方式主要有:
校验和
计算方式:在数据传输的过程中,将发送的数据段都当做一个16位的整数。将这些整数加起来。并且前面的进位不能丢弃,补在后面,最后取反,得到校验和。
发送方:在发送数据之前计算检验和,并进行校验和的填充。
接收方:收到数据后,对数据以同样的方式进行计算,求出校验和,与发送方的进行比对。
序列号(ACK)和确认应答
TCP
传输时将每个字节的数据都进行了编号,这就是序列号。确认应答:TCP
传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答。也就是发送 ACK
报文。这个 ACK
报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发。序列号的作用不仅仅是应答的作用,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据。这也是 TCP
传输可靠性的保证之一。
超时重传
在进行TCP传输时,由于确认应答与序列号机制,也就是说发送方发送一部分数据后,都会等待接收方发送的 ACK
报文,并解析 ACK
报文,判断数据是否传输成功。如果发送方发送完数据后,迟迟没有等到接收方的 ACK
报文,这该怎么办呢?而没有收到 ACK
报文的原因可能是什么呢?
首先,发送方没有介绍到响应的 ACK
报文原因可能有两点:
- 数据在传输过程中由于网络原因等直接全体丢包,接收方根本没有接收到。
- 接收方接收到了响应的数据,但是发送的
ACK
报文响应却由于网络原因丢包了。
TCP在解决这个问题的时候引入了一个新的机制,叫做超时重传机制。简单理解就是发送方在发送完数据后等待一个时间(500ms的整数倍),时间到达没有接收到 ACK
报文,那么对刚才发送的数据进行重新发送。如果是刚才第一个原因,接收方收到二次重发的数据后,便进行 ACK
应答。如果是第二个原因,接收方发现接收的数据已存在(判断存在的根据就是序列号,所以上面说序列号还有去除重复数据的作用),那么直接丢弃,仍旧发送 ACK
应答。
流量控制
接收端在接收到数据后,对其进行处理。如果发送端的发送速度太快,导致接收端的结束缓冲区很快的填充满了。此时如果发送端仍旧发送数据,那么接下来发送的数据都会丢包,继而导致丢包的一系列连锁反应,超时重传呀什么的。而TCP根据接收端对数据的处理能力,决定发送端的发送速度,这个机制就是流量控制。在TCP协议的报头信息当中,有一个16位字段的窗口大小。在介绍这个窗口大小时我们知道,窗口大小的内容实际上是接收端接收数据缓冲区的剩余大小。这个数字越大,证明接收端接收缓冲区的剩余空间越大,网络的吞吐量越大。接收端会在确认应答发送 ACK
报文时,将自己的即时窗口大小填入,并跟随 ACK
报文一起发送过去。而发送方根据 ACK
报文里的窗口大小的值的改变进而改变自己的发送速度。如果接收到窗口大小的值为0,那么发送方将停止发送数据。并定期的向接收端发送窗口探测数据段,让接收端把窗口大小告诉发送端。
滑动窗口(以字节为单位)
- 假定
A
收到来自B
的确认报文段,其中窗口是 20 字节,确认号是 31 (表明B
期望收到的下一个序号是 31)。根据这两个数据,A
构造出自己的发送窗口。
发送窗口由前沿和后沿共同确定。发送窗口通常不断向前移动,也有可能不动(一是没有收到新的确认;二是收到了新的确认但对方通知窗口缩小了,因此只有后沿缩小,前沿正好不动)。
描述一个发送窗口的状态需要三个指针:$P_1,P_2,P_3$,指针指向字节序号。
- 小于 $P_1$ 是已经发送并收到确认的部分
- $P_1 - P_2$ 是已经发送但未收到确认的部分
- $P_2 - P_3$ 是窗口内允许发送但尚未发送的部分
- 大于 $P_3$ 是窗口外不允许发送的部分
拥塞控制
拥塞控制是TCP在传输时尽可能快的将数据传输,并且避免拥塞造成的一系列问题。是可靠性的保证,同时也是维护了传输的高效性。
发送方窗口的上限值应取接收方窗口 rwnd 和拥塞窗口 cwnd 两个变量中的较小值:
TCP传输的过程中,发送端开始发送数据的时候,如果刚开始就发送大量的数据,那么就可能造成一些问题。网络可能在开始的时候就很拥堵,如果给网络中在扔出大量数据,那么这个拥堵就会加剧。拥堵的加剧就会产生大量的丢包,就对大量的超时重传,严重影响传输。
TCP拥塞控制由四个部分组成:慢开始,拥塞避免,快重传,快恢复
慢开始
- 在开始发送数据时,先发送少量的数据探路。探清当前的网络状态如何,再决定多大的速度进行传输。这时候就引入一个叫做拥塞窗口(cwnd)的概念。发送刚开始定义拥塞窗口为
1
,在传输的过程中以2的倍数指数增大cwnd
直至其大于ssthreshold
,之后转为拥塞避免,每次收到ACK应答,拥塞窗口加 1。在发送数据之前,首先将拥塞窗口与接收端反馈的窗口大小比对,取较小的值作为实际发送的窗口。
拥塞避免
- 当出现报文丢失时(既发生重传时),认定网络出现拥塞。将
ssthreshold/=2
,并初始化cwnd=1
重新开始算法。
快重传
让发送方尽早知道个别报文段的丢失,以至于不需超时重传。使用快重传可以使整个网络吞吐量提升 20% 。
- 快重传要求接收方不要等待自己发送数据时才捎带确认,而是立即发送确认;即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。
- 如下图所示,发送方只要一连收到 3 个重复确认ACK,就知道接收方没有收到
M3
,而立即重传 M3 。
快恢复
当接收到连续 3 个重复确认时,知道只是丢失了个别报文段,于是不启动慢开始,而是执行快恢复。
- 发送方调整门限值 ssthresh = cwnd / 2;同时设置 cwnd = ssthresh ,立即进入拥塞避免。
- 这样做的好处是避免个别丢失的报文段被误认为是网络拥塞造成。
TCP 和UDP报文段首部
TCP
- TCP 报文段首部前
20
字节固定,后面有4n
字节可根据需要加选项。
- 源端口和目的端口: 各占 2 字节;TCP 的分用功能通过端口实现。
- 序号(seq): 占 4 字节(序号范围 $[0,2^{32}-1]$);TCP 传送的字节流中每一个字节都按顺序编号;序号字段代表本报文段发送数据的第一个字节的序号,例如一报文段序号
301
,最后一个字节序号400
,那么下一个报文段的数据序号应当从401
开始。 - 确认号(ACK):占 4 字节;代表期望收到对方下一个报文段第一个数据字节的序号;例如
B
正确收到一个报文段,序号字段是501
,数据长度是200
字节,则B
期望收到下一个数据序号是701
,即将发送给A
的确认报文段中的确认号置为701
。若确认号 =N
,代表直到序号N-1
的所有数据都已正确收到。 - 数据偏移:占 4 字节;指出 TCP 报文段数据起始处距离 TCP 报文段起始处的距离;能表示的最大十进制数字为 15,因此数据偏移最大值是 60 字节,也是 TCP 首部的最大长度。
- 保留: 占 6 位,保留今后使用,应设置为 0;
- 紧急 URG (urgent): 当 URG = 1 时,表明紧急指针字段有效。发送方 TCP 把紧急数据插入到本报文段数据的最前面。
- 确认 ACK (acknowledgment):仅当 ACK = 1 时确认号字段有效。TCP 规定,在连接建立后所有传送的报文段应将
ACK
置 1 。 - 推送 PSH (push): 当两个应用进程交互式通信时,一段应用进程希望键入一个命令后立即收到对方响应;推送操作很少使用。
- 复位 RST (reset):
RST = 1
代表 TCP 出现严重差错(例如主机崩溃),必须释放连接;RST
还用来拒绝一个非法的报文段或拒绝打开一个连接。 - 同步 SYN (synchronization): 连接建立时用来同步序号。当
SYN = 1
而ACK = 0
时,表明这是一个连接请求报文段。SYN = 1
和ACK = 1
就表示连接接受。 - 终止 FIN (finish): 用来释放一个连接。当
FIN = 1
时,表明发送方数据已经发送完毕,并要求释放连接。 - 窗口: 占 2 字节;指发送本报文段的一方的接收窗口(窗口大小是由接收方定的,作为发送方设置其发送窗口的依据)。窗口字段明确指出了现在允许对方发送的数据量。窗口值是动态变化的。
- 检验和: 占 2 字节;检验范围包括首部和数据两部分。计算检验和前需要在 TCP 报文段前面加上 12 字节的伪首部,格式与 UDP 伪首部一样,但应把第 4 个字段中的 17 改为 6 (TCP 协议号为 6 ),把第 5 个字段中 UDP 长度改为 TCP 长度。
- 紧急指针:占 2 字节;仅在
URG = 1
时才有意义,指出本报文段中紧急数据的字节数(紧急数据后都是普通数据),紧急指针指出了紧急数据的末尾所在报文段中的位置;窗口为 0 时也可发紧急数据。 - 选项: 长度可变,最长 40 字节。无选项时, TCP 首部长度为 20 字节。
UDP
相应的,UDP
的报文段只有源端口+目的端口+长度+检验和: 各占 2 字节,首部长度为8字节。
长度字段:占16
比特。标明 UDP
头部和 UDP
数据的总长度字节,UDP
首部的长度为固定的 8
个字节,加上 UDP
数据长度就是长度大小,UDP
数据长度可以通过 wireshark
抓包看到。
三次握手四次挥手
三次握手
第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN©。此时客户端处于 SYN_SEND 状态。
首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。
第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN + 1 作为ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。
在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y。
第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。
确认报文段ACK=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。
发送第一个SYN的一端将执行主动打开(active open),接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open)。
四次挥手
A 发送 TCP 连接释放报文,进入 FIN-WAIT-1 状态,等待 B 的确认;
B 收到报文段后立即发出确认,并进入 CLOSE-WAIT 状态;此时 A 到 B 的单向连接已经被释放, TCP 连接处于半关闭状态;B 继续向 A 传输未完成的数据。
A收到 B 的确认后,进入 FIN-WAIT-2 状态,等待 B 的连接释放报文段;
若 B已经将所有数据向 A 发送完毕,则向 A发送 TCP 连接释放报文,并进入 LAST-ACK 状态,等待 A 的确认;
A收到B的连接释放报文段后,立即发出确认,然后进入TIME-WAIT状态,必须经过时间等待计时器 设置的时间2MSL(4 min)后,A才进入CLOSED状态,这是因为:
第一: 由于 A 到 B的最后的
ACK
确认报文段有可能丢失,B 可能会超时重传释放连接报文段,而A
就能在2MSL
时间内收到这个重传的连接释放报文段,并重传确认且重新启动2MSL
计时器。第二: 防止“已失效的连接请求报文段”出现在本连接中,
A
等待2MSL
就可以使本链接持续时间内所产生的所有报文段在网络中消失。MSL是任何报文段被丢弃前在网络内的最长时间
其实可以理解为:seq就是发送者id,ack就是接受者id
一些问题
为什么需要三次握手,两次不行吗?
防止已失效的连接请求又传送到服务器端,因而产生错误:
假设
A
发出的第一个连接请求报文段没有丢失,而是在网络某处长时间滞留了,本来这是一个失效的连接请求;但后续B
收到了它,误认为是A
的连接请求,就向A
发出确认报文段。若不采用三报文握手,此时一个已经失效的连接已经被建立,网络资源被白白浪费了。第二次握手结束时,不能确定客户端的接收能力正常
TCP三次握手,如果第三次客户端发出的信息服务器没收到怎么办
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
ISN(Initial Sequence Number)是固定的吗
就是图中的seq,不是固定的,ISN随时间而变化,因此每个连接都将具有不同的ISN。固定的容易被攻击。
三次握手过程中可以携带数据么
第三次握手的时候,可以携带。前两次握手不能携带数据。
如果前两次握手能够携带数据,那么一旦有人想攻击服务器,那么他只需要在第一次握手中的 SYN 报文中放大量数据,那么服务器势必会消耗更多的时间和内存空间去处理这些数据,增大了服务器被攻击的风险。
而对于第三次握手,此时客户端已经建立了连接,已经能够确认服务器的接收、发送能力正常,这个时候相对安全了,可以携带数据。
挥手为什么需要四次?
因为服务端收到关闭请求的时候可能还有数据要传送,所以需要先把数据传送完,才发FIN请求,所以多了一次。
大量TIME_WAIT造成的影响
在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。
- 高并发可以让服务器在短时间范围内同时占用大量端口,而端口是有限的
- 短连接表示“业务处理+传输数据的时间 远远小于 TIMEWAIT超时的时间”的连接。
持续的到达一定量的高并发短连接,会使服务器因端口资源不足而拒绝为一部分客户服务。
Socket
Socket
是应用层与 TCP/IP
协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket
其实就是一个门面模式,它把复杂的 TCP/IP
协议族隐藏在 Socket
接口后面,对用户来说,一组简单的接口就是全部,让Socket
去组织数据,以符合指定的协议。
先从服务器端说起。服务器端先初始化 Socket
,然后与端口绑定( bind
),对端口进行监听( listen
),调用 accept
阻塞,等待客户端连接。在这时如果有个客户端初始化一个 Socket
,然后连接服务器( connect
),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
socket函数
1 | int socket(int domain, int type, int protocol); |
socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。
- domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
- type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。
- protocol:指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议等等。
bind函数
正如上面所说 bind()
函数把一个地址族中的特定地址赋给 socket
。例如对应 AF_INET
、AF_INET6
就是把一个 ipv4
或 ipv6
地址和端口号组合赋给 socket
。
1 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
listen/connect函数
如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。
1 | int listen(int sockfd, int backlog); |
listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。
connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。
accept函数
TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。
1 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); |
read/write函数
至此服务器与客户已经建立好连接了。可以调用网络I/O进行读写操作了,即实现了网咯中不同进程之间的通信!网络I/O操作有下面几组:
1 | read()/write() |
UDP实现可靠传输:RUDP
UDP要实现可靠传输,可以在应用层实现TCP的那些可靠传输功能,例子是QUIC。
RUDP主要是通过重传来实现可靠传输的。
SOCKET通信中TCP、UDP数据包大小的确定
UDP
和 TCP
协议利用端口号实现多项应用同时发送和接收数据。数据通过源端口发送出去,通过目标端口接收。有的网络应用只能使用预留或注册的静态端口;而另外一些网络应用则可以使用未被注册的动态端口。因为 UDP
和 TCP
报头使用两个字节存放端口号,所以端口号的有效范围是从 0
到 65535
。动态端口的范围是从 1024
到 65535
。
MTU最大传输单元
- 由于以太网最大的数据帧是
1518Bytes
,刨去以太网帧的帧头(DMAC目的MAC地址6Bytes+SMAC源MAC地址6Bytes+Type域2bytes)14Bytes和帧尾CRC校验部分4Bytes 那么剩下承载上层协议的地方也就是Data域最大就只能有1500Bytes这个值我们就把它称之为MTU。 - 数据链路层规定了数据帧中数据字段的最大长度 MTU ,最常用的以太网规定 MTU = 1500 字节,若长度超过
MTU
值,就必须把数据报分片处理。 - 虽然尽可能长的
IP
数据报会使传输效率变高(首部长度占比小),但数据报短路由器转发速度也更快。
因此:
UDP 包的大小就应该是 1500 - IP头(20) - UDP头(8) = 1472(BYTES)
TCP 包的大小就应该是 1500 - IP头(20) - TCP头(20) = 1460 (BYTES)
在用 Socket
编程时, UDP
协议要求包小于 64K
,TCP
没有限定。
不过鉴于Internet上的标准MTU值为576字节,所以建议在进行Internet的UDP编程时,最好将UDP的数据长度控制在**548字节 (576-8-20)**以内。
IP/网络层
IP协议
规定网络地址的协议,叫做IP协议。它所定义的地址,就被称为IP地址。
子网掩码确定ip地址哪部分是网络地址,哪部分是主机地址。
IP协议是不可靠的,非连接。传送的数据可能丢失、重复、失序。
ARP
地址解析协议
同一子网下广播找到对应IP地址的MAC地址。
计算机网络是如何根据IP地址定位到一台主机的
APR 协议作用:已经知道一个机器的IP 地址,需要找出对应的硬件地址。
- RARP 协议:现在的
DHCP
协议包含逆地址解析协议功能,即从硬件地址找出其 IP 地址。
- RARP 协议:现在的
ARP 协议工作原理:网络层使用IP地址,但实际网络链路上传送数据帧时,最终必须使用该网络的硬件地址(MAC)。ARP解决方法是在主机 ARP 高速缓存中存放一个从IP地址到硬件地址的映射表,并实时动态更新(新增或超时删除)。
- 当主机 A 要向主机 B 发送
IP
数据报时,就在其ARP
高速缓存中查看有无主机 B 的IP
地址,如有就查找并写入 MAC 帧,并传输。
- 当主机 A 要向主机 B 发送
有可能查不到主机 B 的
IP
地址,可能主机 B 刚入网,可能主机 A 刚加电(高速缓存为空)。在这种情况下,主机 A 就自动运行ARP
,通过广播请求分组找出主机 B 的硬件地址。ARP 协议工作流程:
- 主机 A 在本局域网上发送一个
ARP
请求分组,在本局域网上所有主机上运行的ARP
进程都收到此请求分组。 - 主机 B 收下这个
ARP
请求,并向主机 A 发送响应分组(普通的单播,发送给主机 A )。同时,把请求分组里 A 的IP
地址到硬件地址的映射写入主机 B 的ARP
高速缓存中。 - 主机 A 收到主机 B 的响应分组后,就在
ARP
高速缓存中写入主机 B 的IP
地址到硬件地址的映射。
- 主机 A 在本局域网上发送一个
ARP生存时间: 超过生存时间(例如 10 ~ 20 分钟)的项目从高速缓存中删掉。这样如果 B 更换了设备, A 无法找到原主机 B ,但过了一段时间, A 的
ARP
高速缓存中已经删除了 B 原先硬件地址,于是 A 重新广播发送ARP
请求分组,找到新的 B 硬件地址。
ICMP/IGMP
ICMP
网际控制报文协议
报文种类:允许主机或路由器报告差错情况和提供有关异常情况的报告
ICMP 差错报告报文和 ICMP 询问报文
ICMP应用:
- Ping :使用了 ICMP 的回送请求和回送回答报文。
- Traceroute:发送的 IP 数据报封装的是无法交付的 UDP 用户数据报,并由目的主机发送终点不可达差错报告报文。
- 源主机向目的主机发送一连串的 IP 数据报。第一个数据报 P1 的生存时间 TTL 设置为 1,当 P1 到达路径上的第一个路由器 R1 时,R1 收下它并把 TTL 减 1,此时 TTL 等于 0,R1 就把 P1 丢弃,并向源主机发送一个 ICMP 时间超过差错报告报文;
- 源主机接着发送第二个数据报 P2,并把 TTL 设置为 2。P2 先到达 R1,R1 收下后把 TTL 减 1 再转发给 R2,R2 收下后也把 TTL 减 1,由于此时 TTL 等于 0,R2 就丢弃 P2,并向源主机发送一个 ICMP 时间超过差错报文。
- 不断执行这样的步骤,直到最后一个数据报刚刚到达目的主机,主机不转发数据报,也不把 TTL 值减 1。但是因为数据报封装的是无法交付的 UDP,因此目的主机要向源主机发送 ICMP 终点不可达差错报告报文。
- 之后源主机知道了到达目的主机所经过的路由器 IP 地址以及到达每个路由器的往返时间。
IGMP
网际组管理协议
NAT
网络地址转换
专用网内部的主机使用本地 IP 地址又想和互联网上的主机通信时,可以使用 NAT 来将本地 IP 转换为全球 IP。
IP 数据报的格式
首部固定字段
版本: 占 4 位;指 IP 协议版本。通信双方使用的 IP 协议版本需一致。
首部长度: 占 4 位;单位是 32 位字(4 字节)。
区分服务: 占 8 位;只有在使用区分服务时才使用,一般情况不使用。
总长度:
占 16 位;指首部和数据长度之和;单位为字节,因此数据报最大长度为 $2^{16}-1=65536$字节
- 数据链路层规定了数据帧中数据字段的最大长度 MTU ,最常用的以太网规定 MTU = 1500 字节,若长度超过 MTU 值,就必须把数据报分片处理。
- 虽然尽可能长的 IP 数据报会使传输效率变高(首部长度占比小),但数据报短路由器转发速度也更快。
标识
:占 16 位。 每产生一个 IP 数据报,计数器 +1。
- 这个标识并不是序号(网络层不负责按序接收);
- 在由于长度超过 MTU 而被分片时,标识字段值被复制到所有分片的标识字段,使各数据报片最后能正确地组装成原来的数据报。
标志
:占 3 位,目前仅前 2 位有意义。
- 最低位记为 MF (More Fragment) ,MF = 1 表示后面“还有分片”数据报,MF = 0 表示这是若干数据报片中的最后一个。
- 中间一位记为 DF (Don’t Fragment) , DF = 1 表示不能分片,DF = 0 才允许分片。
片偏移:
占 13 位;表示数据报在分片后,某片在原分组中的相对位置;单位是 8 字节。
- 每个分片的长度一定是 8 字节(64 位)的整数倍。
生存时间(TTL)
:占 8 位;表示数据报在网络中的寿命。防止数据报在互联网中无限制兜圈子。
- 最初设计 TTL 以秒为单位,消耗时间小于 1s 则将 TTL 减 1 。
- 目前路由器处理数据报时间一般远远小于 1s ,后来 TTL 字段功能改为“跳数限制”,路由器每次转发数据之前把 TTL 减 1 ,当 TTL = 0 就丢失这个数据报。
- 数据报能在互联网中经过路由器的最大数值是 $255=(2^8 - 1)$。若设置 TTL = 1 ,则表示此数据报只能在本局域网中传送。
协议: 占 8 位;表示此数据报中携带的数据使用何种协议,以便接收方主机 IP 层直到应将数据上交给哪个协议处理。
首部校验和: 占 16 位;只检验数据报的首部,不包括数据部分(减少计算量)。
计算方法:同TCP校验和计算方法:对IP头部中的每16bit进行二进制求和,进位加到低位,最后取反
源地址: 占 32 位;
目的地址: 占 32 位。
首部可变部分
- IP 数据报首部的可变部分就是一个选项字段,用来支持排错、测量、安全措施等。
- 长度 1 - 40 字节,取决于选择的项目。
- 可变部分是用来增加 IP 数据报的功能,实际上这些选项很少被使用。很多路由器都不考虑 IP 首部的选项字段,因此新的 IP 版本 IPv6 就将 IP 数据报的首部长度做成固定的。
交换机和路由器的区别
- 工作层次:交换机主要工作在数据链路层,路由器主要工作在网络层
- 转发依据:交换机转发依据的对象是MAC地址,路由器转发依据的对象是IP地址
- 功能:交换机功能较简单,只是将主机连接起来组件局域网,路由器可以将局域网连接起来,还能分割广播域,还能提供防火墙
MAC表、路由表、ARP表的字段
- MAC表
- 路由表
- ARP表