计网疑云
- 作者
- Name
- 青玉白露
- Github
- @white0dew
- Modified on
- Reading time
- 83 分钟
阅读:.. 评论:..
偶然看到一篇推文说“计算机网络的知识繁杂难懂,诸如不同层级的协议、特性相互联系又有所不同,要想学懂计算机网络就得抓住一条主线。” 文中所说的主线是“一个数据包是如何发送出去的”。只有把握住了整个网络脉络主线才不至于被纷繁复杂的网络协议所搞晕,剩下的就是不断的细化,填充这些主干上的细枝末节。
OSI五层数据包的一生
先说说计算机网络的五层结构。
层级 | 作用 | 数据格式 |
---|---|---|
应用层 | 为程序提供数据接口 | 数据包 |
传输层 | 端到端通信、流控制 | 报文段 |
网络层 | 网间路由 | 数据报 |
链路层 | 帧传输**(封装成帧、透明传输、差错检测)** | (以太)帧 |
物理层 | 物理信道传输 | 比特流 |
注:数据包即代表应用程序想要发送出去的原数据。 注2:OSI参考模型是七层,应用层7+表示层6+会话层5融合成了应用层。 封装蜕变
从IP到MAC,网络路由的详细过程
路由的具体细节,极其重要! https://blog.csdn.net/xiaoliuliu2050/article/details/81251925 也许有人会问了“既然已经有了IP地址,那么为什么还需要MAC地址?” 答:个人推崇这个回答,历史的局限性以及架构的分层级——为什么IP与MAC地址并存? 这一个回答也有意思——有了 IP 地址,为什么还要用 MAC 地址? IP地址与MAC地址共存这其实更多的是历史造就的技术原因。 因特网(TCP/IP)原本可没想到自己会成为覆盖全球的网络,因此就存在很多的漏洞:IP地址不够、没有考虑OSI其他层的关系等,要想它的运行在全球就需要基于以太网(底部两层),这才有了IP与MAC地址共存。 因此,将IP和传输网络分开,可以更好地根据需要使用各种通信技术(比如WIFI、ADSL等,那就不是MAC了而是其他协议的帧传输单位)
输入URL到显示过程中发生了什么?
这个部分主要根据《网络是怎么连接》一书总结的。 URL:Uniform Resource Locator,统一资源定位符。 URI:Uniform Resource Identifier,统一资源标识符. (1) 应用层 浏览器首先会根据URL确定使用的协议是什么,如HTTP、FTP。 以HTTP协议为例,先解析URL生成发送给服务器web的请求消息。 请求消息中包含的内容是“对什么”和“进行怎样的操作”两个部分。 接收到请求消息(请求消息与响应消息即是是****HTTP协议的重点)之后,web服务器完成对应操作,将结果存放于响应消息之中发送回浏览器。 返回响应消息之后,浏览器会将数据提取出来并显示在屏幕上。如果网页中还包括图片等资源,会在网页中的相应位置嵌入表示图片文件的标签的控制信息。浏览器会在屏幕上留下显示图片的空间(这就是为什么经常出现网页图片加载不全了),而后再次访问web服务器获取图片(比如利用Base64)。每条请求消息只能写一个URI。也就说说如果一个网页包含3张图片,那么需要向Web服务器进行4次请求(1+3)。 Base64是网络上最常见的用于传输8Bit字节码的编码方式之一。 (2)DNS查询 在生成HTTP消息之后,Web浏览器需要委托操作系统将消息发送给Web服务器。在进行这一操作之前,需要先查询域名对应的IP地址(就是知道发往何方)。 Ipv4是4字节32比特的地址,分为主机号和网络号。主机号全为0,代表整个子网;主机号全为1,代表子网内广播。 DNS查询的步骤如下:查看浏览器缓存-》查看本地缓存-》DNS服务器; 由于很难直接记住IP地址,因此人们选择用域名来代替网络,但是在网络传输的过程中,需要一种协议来将域名转换为IP,这就是DNS协议。 注:真的存在以名称来确定通信对象的网络,Windows的原型PC-Networks就是。以名称来确定对象的方法会造成效率低下的原因就在于,域名的长度不固定,处理不固定的数据要比处理固定长度的数据复杂。 DNS解析这一操作是包含Socket库中的。也就是说根据域名查询 IP 地址时,浏览器会使用 Socket 库中的解析器来实现DNS解析功能。 建立套接字管道 委托操作系统进行消息的发送之前,需要将两端传输“管道”连通。这也是基于Socket组件来实现的。 收发数据的操作分为若干个阶段,可以大致总结为以下 4 个。 (1)创建套接字**(创建套接字阶段)** (2)将管道连接到服务器端的套接字上**(连接阶段)** (3)收发数据**(通信阶段)** (4)断开管道并删除套接字**(断开阶段)** 注:应用程序是通过“描述符”这一类似号码牌的东西来识别套接字的。 注2:常用的应用层协议的端口号是众所周知的,而服务器连接之后为客户随机分配了一个端口号(Connfd)。 常见端口号 http://www.360doc.com/content/20/1229/17/15915859_954215773.shtml (3)TCP/IP协议栈 如何将消息发送给服务器的?这一过程是网络控制软件(协议栈)与网络硬件(网卡)共同完成的,其基本结构如下:
连接服务器 什么是“连接”? 连接实际上是通信双方交换控制信息,在套接字中记录这些必要信息并准备数据收发的一连串操作,像客户端将IP****地址和端口号告知服务器这样的过程就属于交换控制信息的一个具体的例子。 对于常见的TCP通信而言,它的控制信息主要存在于报头。 收发数据 完成连接之后就进行HTTP请求消息的发送和接收。 在发送方,消息的发送是利用Socket库的write函数来执行的,但是数据是否是一次性发送需要根据发送策略来决定的,一般会积累到一定量发送(不然网络中发送很多小包,影响效率)。 有以下判断要素:- MTU(网络包最大长度Maximum Transmission Unit),以太网一般1500字节,减去头部长度即是MSS(最大数据长度)。因此积累到接近MSS发送可以提高效率。
- 时间:定时之后发送数据,不管有没有达到MSS。
当IP数据报过大时,需要对大数据进行拆分,拆成MSS的长度来发送。 发送请求消息之后,调用read来获取服务器的响应信息。 MTU: Maximum Transmit Unit,最大传输单元,即物理接口(数据链路层)提供给其上层(通常是IP层)最大一次传输数据的大小;以普遍使用的以太网接口为例,缺省MTU=1500 Byte,这是以太网接口对IP层的约束,如果IP层有<=1500 byte 需要发送,只需要一个IP包就可以完成发送任务;如果IP层有> 1500 byte 数据需要发送,需要分片才能完成发送,这些分片有一个共同点,即IP Header ID相同。 ———————————————— **MSS:**Maximum Segment Size ,TCP数据提交给IP层最大分段大小,不包含TCP Header和 TCP Option,只包含TCP Payload ,MSS是TCP用来限制application层最大的发送字节数。如果底层物理接口MTU= 1500 byte,则 MSS = 1500- 20(IP Header) -20 (TCP Header) = 1460 byte,如果application 有2000 byte发送,需要两个segment才可以完成发送,第一个TCP segment = 1460,第二个TCP segment = 540。 断开连接 在发送完数据过后,任何一方都可以主动申请断开连接,这一步调用的是Socket库中的close函数。 调用该函数过后,协议栈生成包含FIN为1的TCP头部。而后委托IP模块发送给另外一方。(进行四次握手) 不过,套接字并不会立即被删除,而是会等待一段时间之后再被删除,等待这段时间是为了防止误操作。 比如四次挥手最后客户端的ACK消息丢失了,会使服务器重发FIN,若客户端有新程序使用了相同的端口,就会造成连接中断。(即混淆)
应用层
HTTP/S
请求响应消息体=请求行(重点部分:方法、URI、http版本)+消息头+消息体(客户端向服务器发送的数据,如POST) 消息头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息,如支持语言、浏览器版本;
http请求:https://www.jianshu.com/p/eb3e5ec98a66 响应消息状态码: HTTP主要方法 注:GET 方法能够发送的数据只有几百个字节,如果表单中的数据超过这一长度,则必须使用 POST 方法来发送。Get和Post的区别
其实两者只不过是实现的不同。 实际上的区别: GET的语义是请求获取指定的资源。GET方法是安全(是否会影响服务器状态)、幂等(重复提交是否出错)、可缓存的。 POST的语义是根据请求负荷(报文主体)对指定的资源做出处理,具体的处理方式视资源类型而不同。POST不安全,不幂等,(大部分实现)不可缓存。
- 最直观的就是语义上的区别,get用于获取数据,post用于提交数据。
- get参数有长度限制(受限于url长度,具体的数值取决于浏览器和服务器的限制如几百个字节),而post无限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。GET参数通过URL传递,POST放在Request body中。 GET在浏览器回退时是无害的,而POST会再次提交请求。 3.GET产生一个TCP数据包;POST产生两个TCP数据包。 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
HTTP可以用UDP
**很遗憾不能,**HTTP使用TCP,是因为TCP实现了可靠的传输连接。 如果用UDP,因为连接不可靠,所以网页源文件传输后不是会错误百出嘛。如果在应用层面实现一套自己的重传、确认等机制,会给浏览器增加极大负担。假如使用udp,要解决很多问题比如丢包,流控,拥塞,重包检测,相当于要在应用层实现很多的功能。 夭寿啦!!!HTTP3.0就是基于UDP?
HTTP的演变
1、HTTP1.0需要使用keep-alive参数才能建立长连接,但HTTP1.1默认长连接 2、HTTP1.0是没有host域的,HTTP1.1才支持这个参数。 什么是Host域呢? 1、Host 表示当前请求要被发送的目的地,说白了就是当前请求目标资源的host(同一个域名可以被解析成同一个IP),仅包括域名和端口号,如test.haoji.me。在任何类型请求中,request都会包含此header信息。 2、Origin 表示当前请求资源所在页面的协议和域名,如http://blog.haoji.me,特别注意:这个参数一般只存在于CORS跨域请求中,普通请求没有这个header! 3、Referer 表示当前请求资源所在页面的完整路径:协议+域名+查询参数(注意不包含锚点信息),如http://blog.haoji.me/http-host-origin-referer.html?a=1&b=2,所有类型的请求都包含此header。 3、HTTP1.1支持先只发头信息,如果服务器认为客户端有权限请求服务器则返回100,否则返回401,客户端收到100时才发生主体部分,这样节约带宽,如POST。 https://blog.csdn.net/glpghz/article/details/106063833 HTTP2.0实现了多路复用,即并行执行请求,而之前的HTTP1.1是串行,一个请求未能执行会阻塞其他的请求。
限制于TCP的的缺点:HTTP2.0连接速度慢、队头堵塞、弱网环境表现不佳。 队头堵塞? 队头阻塞 Head-of-line blocking(缩写为HOL blocking)通俗来说就是:一个数据包影响了一堆数据包,它不来大家都走不了。队头阻塞问题可能存在于HTTP层和TCP层。 HTTP2.0协议的多路复用机制解决了HTTP层的队头阻塞问题,但是在TCP层仍然存在队头阻塞问题。 TCP协议在收到数据包之后,这部分数据可能是乱序到达的,但是TCP必须将所有数据收集排序整合后给上层使用,如果其中某个包丢失了,就必须等待重传,从而出现某个丢包数据阻塞整个连接的数据使用。 HTTP3.0 QUIC (Quick UDP Internet Connections), 快速 UDP 互联网连接。QUIC是基于UDP协议的。 谷歌决定选用UDP作为底层可能有很多的考虑:一个是TCP本身的限制,另一个是改造的难度和影响。 上面内容来自:QUIC的介绍还有这篇文章:HTTP/3竟然基于UDP HTTP 协议这些年都经历了啥?HTTP和HTTPS区别
先回答这个:https基于SSL/TLS和http协议构建的可加密传输、身份认证的网络协议,比http更加安全。前者是443端口,后者是80端口。 详细解释: 1、https协议需要到ca证书,一般免费证书很少,需要交费。 2、http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。 3、http和https前者是80,后者是443。 4、http的连接很简单,https需要认证环节。
HTTPS的优缺点
优点是更加安全可靠(并非绝对安全,例如掌握根证书的机构)、基于SSl可加密; 缺点是https需要CA证书,基于ssl加密,但是加载和性能消耗提高,并非完全安全。(根证书机构可以进行欺诈)
HTTPS连接过程
回答:HTTPS连接主要分为两个阶段,一个是连接建立(CA验证),一个是数据传输(SSL加密)。 PS:对称密钥是啥? 其实就是生成的一组随机数,用来加密传输的数据。https而加密过程是使用了非对称加密实现。但其实:HTTPS 在内容传输的加密上使用的是对称加密(较非对称加密效率高),非对称加密只作用在证书验证阶段。 对称加密与非对称加密不太理解?那就看这个:链接 私钥加密公钥解密,公钥加密私钥解密。(以前一直以为只能私钥来解密)
CA证书怎么验证?
也就是说:证书验证阶段,浏览器(客户端)怎么才相信证书合法呢? 在接收到证书之后: 1)验证域名、有效期等信息是否正确:证书上都有包含这些信息,比较容易完成验证; 2)判断证书来源是否合法:每份签发证书都可以根据验证链查找到对应的根证书,操作系统、浏览器会在本地存储权威机构的根证书,利用本地根证书可以对对应机构签发证书完成来源验证: 3)判断证书是否被篡改:需要与 CA 服务器进行校验; 4)判断证书是否已吊销(可用):通过CRL(Certificate Revocation List 证书注销列表)和 OCSP(Online Certificate Status Protocol 在线证书状态协议)实现,其中 OCSP 可用于第3步中以减少与 CA 服务器的交互,提高验证效率。 这是一整段有关https加密的原理及应用分析: https://www.cnblogs.com/imstudy/p/12015889.html
没有CA验证?
见下图,无法防止中间人劫持:
窃听者可以伪造服务器的公钥与客户端通讯,客户端以为是跟服务器通讯,其实是与窃听者在通讯,后果可想而知。数字证书和数字加密
数字签名 发邮件的例子,假设A用自己的私钥对Email加密发送,这存在下面问题: 对文件本身加密可能是个耗时过程,比如这封Email足够大,那么私钥加密整个文件以及拿到文件后的解密无疑是巨大的开销。 数字签名(主要是为了防止修改)可以解决这个问题: 1.A先对这封Email执行哈希运算得到hash值简称“摘要”,取名h1 2.然后用自己私钥对摘要加密,生成的东西叫“数字签名” 3.把数字签名加在Email正文后面,一起发送给B (当然,为了防止邮件被窃听你可以用继续公钥加密,这个不属于数字签名范畴) 4.B收到邮件后用A的公钥对数字签名解密,成功则代表Email确实来自A,失败说明有人冒充 5.B对邮件正文执行哈希运算得到hash值,取名h2 6.B 会对比第4步数字签名的hash值h1和自己运算得到的h2,一致则说明邮件未被篡改 CA证书的指纹?CA证书到底是啥? CA机构在下发CA证书之后会附带一个指纹,其实是证书的hash值,便于浏览器查验这个证书是否有误。 去找"证书中心"(certificate authority,简称CA),为公钥做认证。证书中心用自己的私钥,对A的公钥和一些相关信息一起加密,生成"数字证书"(Digital Certificate) https://blog.csdn.net/zhaisharap/article/details/89706592 (原版是这个) https://www.jianshu.com/p/4932cb1499bf
DHCP
有什么用? 集中的管理、分配IP地址,使网络环境中的主机动态的获得****IP地址、Gateway地址、DNS服务器地址等信息。 怎么工作? 由网络主机驱动,服务器才分配IP信息给它。如下图所示:
(要选择一个DHCP服务器来作为自己的服务方) https://blog.csdn.net/lm409/article/details/80298225 用了那个传输层协议? **UDP(返回DNS)和TCP(区域大批量同步)**都用过了:链接传输层
TCP/UDP两者有何区别?
TCP(Transmission Control Protocol传输控制协议)是一种面向连接的,可靠的,基于字节流的传输通信协议。 UDP(User Datagram Protocol用户数据报协议),无连接的,不可靠的,数据报协议。 区别: 1、TCP是面向连接的(在客户端和服务器之间传输数据之前要先建立连接),UDP是无连接的(发送数据之前不需要先建立连接) 2、TCP提供可靠的服务(通过TCP传输的数据。无差错,不丢失,不重复,且按序到达);UDP提供面向事务的简单的不可靠的传输。 3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性比较高的通讯或广播通信。 4、每一条TCP连接一到一的,UDP支持一对一,一对多和多对多(存疑)的交互通信。 5、TCP对系统资源要求比较多,UDP对系统资源要求比较少 6、TCP是流模式,UDP是数据报模式 PS:http和tcp有啥关系? 依靠和被依靠的关系,http定义数据,tcp负责传输。 https://www.cnblogs.com/baizhanshi/p/8482612.html
TCP
TCP报文
TCP的学习建议直接从其报文入手,报文格式如下:
参考博客:链接 关键参数的解释(重点):- 序号/确认号:是TCP可靠传输的关键部分。
序号是本报文段发送的数据组的第一个字节的序号。在TCP传送的流中,每一个字节一个序号。 Eg,一个报文段的序号是300,且本报文段数据部分共有100字节,则下一报文段的序号是401(这就保证了TCP传输的有序性)。 确认号,即ACK,指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当ACK标志为1时才有效。比如建立连接时,SYN报文的ACK标志位为0。 注:实际使用中,序号并不是从1开始的,因为这样会使通信容易泄露,一般是随机数。确认初始序号的这一过程是在与服务器建立通信时主机确定的; 注:在收到ACK之前,消息都存在缓冲区里,以便重发;
- 数据偏移/首部长度:4bits。
指示了数据区在报文段中的起始偏移值。由于首部可能含有可选项内容,因此TCP报头的长度是不确定的。 不含任何任选字段长度为20字节,4位首部长度字段所能表示的最大值为1111,转化为10进制为15,15*32/8 = 60,故报头最大长度为60字节。
- 保留位:留作以后协议版本更新之后的用途。
- 控制位:一共有六位,一位一字节
URG:紧急指针(只是这么说,但是对方如何响应看应用层的实现) ACK:确认应答标志,0时表示不含确认信息,忽略该位; PSH:表示该信息应尽快给应用程序,而不是在缓冲区; RST:连接重置,主机崩溃或拒绝非法连接; SYN:同步信号,连接过程:连接请求中,SYN=1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1。(待会讲解三次握手) FIN:数据结束,释放连接的标志(后面就是四次挥手了)
- 滑动窗口大小:用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小16bit字段,因而窗口大小最大为65535。
- 校验和:用作TCP头部和数据部分的奇偶校验;
- 紧急指针: URG置 1 时有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。
紧急数据:发送方认为该数据优先级极高,使接收方即便没有处理完数据就继续接收(至于接收方收到之后干什么由它自己决定),参考:链接
- 可选项/填充:如最长报文大小MSS(Maximum Segment Size),表示本端可接受的大小。填充位是为了保证头部是32的倍数。
MTU:一个网络包的最大长度,以太网中一般为 1500 字节。 MSS:除去头部之后,一个网络包所能容纳的 TCP 数据的最大长度。
- 数据部分:可以为0;
TCP的四种计时器
https://blog.csdn.net/youzi_yun/article/details/77488808 TCP共使用以下四种计时器:重传计时器、持续计时器、保活计时器和时间等待计时器。 重传计时器当TCP发送报文段时,创建该特定报文段的重传计时器。可能发生两种情况:
- 若在计时器截止时间到之前收到了对此特定报文段的确认ACK,则撤销此计时器。
- 若在收到了对此特定报文段的确认之前计时器截止期到,则重传此报文段,并将计时器复位。
持续计时器 窗口大小通知:接收方可接收缓存的数据大小;接收方发送窗口大小通知给传送方,传送方才能发送数据,如果接收方缓存已满,会发送零窗口大小通知给发送方。 为了对付零窗口大小通知,TCP需要另一个计时器。 假定接收TCP宣布了窗口大小为零:发送TCP就停止传送报文段,直到接收TCP发送确认并宣布一个非零的窗口大小。但这个确认可能会丢失。我们知道在TCP中,对确认是不需要发送确认的。若确认丢失了,接收TCP并不知道,而是会认为它已经完成任务了,并等待着发送TCP接着会发送更多的报文段。但发送TCP由于没有收到确认,就等待对方发送确认来通知窗口的大小。双方的TCP都在永远地等待着对方。 为了解决这种死锁等待情况,TCP为每一个连接使用一个坚持计时器。**当发送TCP收到一个窗口大小为零的确认时,就启动坚持计时器。**当坚持计时器期限到时,发送TCP就发送探测报文段。这个报文段只有一个字节的数据,有一个序号,但它的序号永远不需要确认;甚至在计算对其他部分的数据的确认时该序号也被忽略。探测报文段提醒对方:确认已丢失,必须重传。 坚持计时器的值设置为重传时间的数值。但是,若没有收到从接收端来的响应,则需发送另一个探测报文段,并将坚持计时器的值加倍和复位。发送端继续发送探测报文段,将坚持计时器设定的值加倍和复位,直到这个值增大到门限值(通常是60秒)为止。在这以后,发送端每隔60秒就发送一个探测报文段,直到窗口重新打开。 保活计时器 保活计时器使用在某些实现中,用来防止在两个TCP之间的连接出现长时期的空闲。 假定客户打开了到服务器的连接,传送了一些数据,然后就保持静默了。也许这个客户出故障了。在这种情况下,这个连接将永远地处理打开状态。 要解决这种问题,在大多数的实现中都是使服务器设置保活计时器。每当服务器收到客户的信息,就将计时器复位。超时通常设置为2小时。 若服务器过了2小时还没有收到客户的信息,它就发送探测报文段。若发送了10个探测报文段,每一个相隔75秒,还没有响应就假定客户出了故障,因而就终止该连接。 时间等待计时器 2MSL时间等待计时器是在连接终止期间使用,即:TCP四次挥手最后一次。 当TCP关闭一个连接时,它并不认为这个连接马上就真正地关闭了。 时间等待期间中连接还处于一种中间过渡状态。主要是为了让重复的FIN报文段到达目的站,将其丢弃。 这个计时器的值通常设置为一个报文段的寿命期待值的两倍。
拥塞控制
有什么用? 是为了解决过多的数据注入到网络,导致网络奔溃,超过负荷变卡;这是通过改变窗口来解决的。 什么是窗口? 即是缓冲区,对每一次发送的数据大小进行限制;目标是最大化利用网络上瓶颈链路的带宽。 具体来说?https://zhuanlan.zhihu.com/p/76023663 网络中容纳数据包数量=链路带宽往返时延(宽度乘以长度)。 为了防止网络达到上限,通过拥塞窗口来动态估计传输效率。 怎么实现最佳的拥塞窗口? 不停地尝试:只要网络中没有出现拥塞,拥塞窗口的值就可以再增大一些;但只要网络出现拥塞,拥塞窗口的值就应该减小一些。 有什么算法策略?(linux Reno算法) 见下图,附参考链接链接 **慢启动(翻倍递增到阈值)、拥塞避免(*+1直到峰顶变为一半)、快重传(直接重传而不等下一波数据)和快恢复(快速+1恢复)。
快重传指的是当接受方接收到顺序错误得数据时不接收数据,同时重复发起对于之前数据的确认,发动到第三次,发送方得知自己的一部分数据再发送中丢失,立即发起重传,不需要等待下一次发送信息时一起发送过去.,且重传时触发和拥塞一样得情况,进入快恢复阶段 快速重传的更进一步解释详解?链接流量控制
https://www.cnblogs.com/kubidemanong/p/9987810.html 什么是流量控制? 对发送方发送速率的控制,我们称之为流量控制。(防止接收方忙不过来) 如何控制? 接收方发送确认报文的同时发送自身剩余缓存区大小(参见TCP报文),从而发送方进行调整。如果满了,发送方停止;定时向接收方查询是否可以发送咯。 整个流程如下:
那么什么时候继续发送? 我们可以采用这样的策略:当接收方处理好数据,接受窗口 win > 0 时,接收方发个通知报文去通知发送方,告诉他可以继续发送数据了。当发送方收到窗口大于0的报文时,就继续发送数据。 不过这时候可能会遇到一个问题,假如接收方发送的通知报文,由于某种网络原因,这个报文丢失了,这时候就会引发一个问题:接收方发了通知报文后,继续等待发送方发送数据,而发送方则在等待接收方的通知报文,此时双方会陷入一种僵局。 为了解决这种问题,我们采用了另外一种策略:当发送方收到接受窗口 win = 0 时,这时发送方停止发送报文,并且同时开启一个定时器,每隔一段时间就发个测试报文去询问接收方,打听是否可以继续发送数据了,如果可以,接收方就告诉他此时接受窗口的大小;如果接受窗口大小还是为0,则发送方再次刷新启动定时器。 上述的方案流程如下: 什么是糊涂窗口综合征? 当接收方的缓存窗口不够时时,发送方停止;当接收方缓存空1字节时,通知发送方发送,这样效率极低! 正确的做法:接收方等待一段时间或缓存到达一定阈值比如一半时才继续发送。ACK等待时间及窗口
当网络拥堵时,ACK返回时间变慢,需要延长其等待时间,那么如何兼顾网络效率和时间呢? TCP 采用了动态调整等待时间的方法,这个等待时间是根据 ACK 号返回所需的时间来判断的。 具体来说,TCP会在发送数据的过程中持续测量ACK号的返回时间,如果ACK号返回变慢,则相应延长等待时间;相对地,如果ACK号马上就能返回,则相应缩短等待时间。 如果一次发一个包就等待ACK,效率未免太低,于是就有了滑动窗口这一概念:一次性发多个包,如有错误再重发。 接收窗口和滑动窗口详解链接
三次握手与四次挥手
值得注意的是,三次握手与四次挥手的目的是建立可靠连接!是让两方都进入可传输/发送状态! 结合TCP的状态机来学习:
- 三次握手:
三次握手本质是为了通信双方互相通知对方自己的ISN(Inital Sequence Number初始化序号),保证作为以后的数据通信的信号,保证应用层收到的数据不会因为网络上的传输问题而乱序。 注:该ISN的序号之所以采用随机而不是从1开始,是为了防止跟之前的连接混淆; 假设A客户端 B服务器 第一次:A向B发送同步SYN,选择一个初始序号x,客户端进入SYN-SENT 第二次:B收到请求报文,如果同意建立连接,回复SYNACK,并选择自己的初始序号y,同时将确认序号设置为客户序号+1即x+1,服务器端进入SYN_RCVD 第三次:A收到ACK,再次发送ACK,并确认B序号y+1,发送结束后,A进入ESTABLISHED,B接收到ACK后也进入ESTABLISHED,握手结束。
- 四次挥手:
四次挥手本质上其实只有2次,4次是因为两端都需要Fin和Ack,只不过一方被动一方主动,若两边同时发起断开,可能两边同时进入CLOSING状态,同时进入timewait。另外在单端关闭后进入closewait阶段,服务器可以继续向客户端发送数据。 假设A客户端 B服务器 第一次:A向B发送FIN,表示没有要发的数据了请求关闭,但可以接收,进入FIN_WAIT_1状态 **第二次:**B回复ACK确认已经收到了,但自己还没有准备要关闭(可能还有数据要发送),这时处于半关闭状态,这个状态要持续一段时间,这时B处于CLOSEWAIT状态,A处于FIN_WAIT_2状态 **第三次:**B准备关闭,向A发送FIN,B进入LAST_ACK (当B不准备发送数据时,二、三即可合并,变成“三次挥手”) 第四次:A回复ACK并进入TIME_WAIT,等待可能要求重传ACK包,B接收到ACK后CLOSE,在等待2MSL后,A认为B正常关闭,则进入CLOSE。
Time_wait是2MSL呢?
链接 根据第三版《UNIX 网络编程 卷 1》2.7 节,TIME_WAIT 状态的主要目的有两个: +优雅的关闭 TCP 连接,也就是尽量保证被动关闭的一端收到它自己发出去的 FIN 报文的 ACK 确认报文; +处理延迟的重复报文,这主要是为了避免前后两个使用相同四元组的连接中的前一个连接的报文干扰后一个连接。 +1假如现在 A 发送 ACK 后,最坏情况下,这个 ACK 在 1MSL 时到达 B;此时 B 在收到这个 ACK 的前一刹那,一直在重传 FIN,这个 FIN 最坏会在 1MSL 时间内消失。因此从 A 发送 ACK 的那一刹那开始,等待 2MSL 可以保证 A 发送的最后一个 ACK,和 B 发送的最后一个 FIN 都在网络中消失。 +2等待 2MSL 的真正目的是为了避免前后两个使用相同四元组的连接中的前一个连接的报文干扰后一个连接,换句话说,就是为了让此次 TCP 连接中的所有报文在网络中消失。
为什么三次握手、四次挥手?
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。在另一部经典的《计算机网络》一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。这两种不用的表述其实阐明的是同一个问题。 两种解答思路: **第一种:**谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。” **第二种:**这个问题的本质是, 信道不可靠, 但是通信双发需要就某个问题达成一致. 而要解决这个问题, 无论你在消息中包含什么信息, 三次通信是理论上的最小值. 所以三次握手不是TCP本身的要求, 而是为了满足"在不可靠信道上可靠地传输信息"这一需求所导致的. 请注意这里的本质需求,信道不可靠, 数据传输要可靠. 三次达到了, 那后面你想接着握手也好, 发数据也好, 跟进行可靠信息传输的需求就没关系了. 因此,如果信道是可靠的, 即无论什么时候发出消息, 对方一定能收到, 或者你不关心是否要保证对方收到你的消息, 那就能像UDP那样直接发送消息就可以了.”。这可视为对“三次握手”目的的另一种解答思路。
因为TCP是一个全双工连接,一端发送完了数据不代表另一端没有数据要发送了,所以需要双方各自关闭一次,而连接的时候为什么只需要三次握手呢,是因为第二次握手的过程是同时包含了SYN和ACK的,因为连接的时候没有必要像断开那样分两个方向断开连接,因为连接都还没建立,双方肯定没有数据在发送。 因为TCP是可靠协议,client告诉server我想断开连接,需要收到server的回复,也就是ack,这样client才能知道server知道我想断开连接了,这里就体现了TCP是可靠协议的“可靠”二字的含义。到这里就是两次握手了。 同样的,server在知道client想断开后,赶紧把剩下的数据传输完,再发一个fin(第三次)给client告诉client我即将断开了,这个信息server也需要收到client的ack,这样才可靠嘛!这个ack是第四个包,俗称第四次握手。 之所以不是像建立连接那样三次握手,就是因为挥手时候第三次和第四次之间,server还需要去把剩下的数据发送完。 存疑 原本需要2+2; 但是如果server在接收到client之后,也无话可说,那么就可以将自己的FIN和ACK合在一起发送啊! 这其实就是TCP的Delayed ACK,但可能会造成网络应用延迟增大: https://cloud.tencent.com/developer/article/1004356
SYN_FLOOD的出现和解决方法
如果服务器第二步之后没有收到ACK,它会再次发送SYN-ACK,而且存在重传间隔和时间,有的就用这种方法消耗服务器资源。这就被称为SYN_FLOOD(SYN攻击)。 如何应对SYN 攻击呢? 设置一定的重传次数;SYN队列大小(即半连接); 还可以利用tcp_syncookie来判断是否是攻击者(如果是攻击者不会回复);syncookie的详细解释:链接 syncookie可以保证服务器如何在不分配资源的情况下
- 验证之后可能到达的****ACK的有效性,保证这是一次完整的握手
- 获得SYN报文中携带的TCP****选项信息
SYN Cookie技术可以让服务器在收到客户端的SYN报文时,不分配资源保存客户端信息(也就是说服务器没有任何损失),而是将这些信息保存在SYN+ACK的初始序号和时间戳中。对正常的连接,这些信息会随着ACK报文被带回来,而后才会真正建立其链接**(而之前服务器会建立一个半连接,消耗资源)** (以下才是重点!) TCP连接建立时,双方的起始报文序号是可以任意的。SYN cookies利用这一点,按照以下规则构造初始序列号:
- 设t为一个缓慢增长的时间戳(典型实现是每64s递增一次)
- 设m为客户端发送的SYN报文中的MSS选项值
- 设s是连接的元组信息(源IP,目的IP,源端口,目的端口)和t经过密码学运算后的Hash值,即s = hash(sip,dip,sport,dport,t),s的结果取低 24 位
则初始序列号n为:
- 高 5 位为t mod 32
- 接下来3位为m的编码值
- 低 24 位为s
当客户端收到此SYN+ACK报文后,根据TCP标准,它会回复ACK报文,且报文中ack = n + 1,那么在服务器收到它时,将ack - 1就可以拿回当初发送的SYN+ACK报文中的序号了!服务器巧妙地通过这种方式间接保存了一部分SYN报文的信息。 接下来,服务器需要对ack - 1这个序号进行检查:
- 将高 5 位表示的t与当前之间比较,看其到达地时间是否能接受。
- 根据t和连接元组重新计算s,看是否和低 24 一致,若不一致,说明这个报文是被伪造的。
- 解码序号中隐藏的mss信息
到此,连接就可以顺利建立了。主要三个缺点:
- MSS的编码只有3位,因此最多只能使用 8 种MSS值
TCP选项,如最大报文段长度****MSS、时间戳timestamp、选择应答使能Sack、窗口缩放因子Wscale等等
- 服务器必须拒绝客户端SYN报文中的其他只在SYN和SYN+ACK中协商的选项,原因是服务器没有地方可以保存这些选项,比如Wscale和SACK
- 增加了密码学运算
TCP保活机制
链接 在需要长连接的网络通信程序中,经常需要心跳检测机制,来实现检测对方是否在线或者维持网络连接的需要。这一机制是在应用层实现的,对应的,在TCP协议中,也有类似的机制,就是TCP保活机制。 为什么需要保活机制? 设想这种情况,TCP连接建立后,在一段时间范围内双发没有互相发送任何数据。思考以下两个问题:
- 怎么判断对方是否还在线。这是因为,TCP对于非正常断开的连接系统并不能侦测到(比如网线断掉)。
- 长时间没有任何数据发送,连接可能会被中断。这是因为,网络连接中间可能会经过路由器、防火墙等设备,而这些有可能会对长时间没有活动的连接断掉。
如何实现保活机制? 保活机制是由一个保活计时器实现的。当计时器被激发,连接一段将发送一个保活探测报文,另一端接收报文的同时会发送一个****ACK作为响应。 工作流程:连接中启动保活功能的一端,在保活时间内连接处于非活动状态,则向对方发送一个保活探测报文,如果收到响应,则重置保活计时器,如果没有收到响应报文,则经过一个保活时间间隔后再次向对方发送一个保活探测报文,如果还没有收到响应报文,则继续,直到发送次数到达保活探测数,此时,对方主机将被确认为不可到达,连接被中断。 保活功能在默认情况下是关闭的。没有经过应用层的请求,Linux系统不会提供保活功能。 相关配置 具体实现上有以下几个相关的配置: 保活时间:默认7200秒(2小时) 保活时间间隔:默认75秒 保活探测数:默认9次 查看Linux系统中TCP保活机制对应的系统配置如下(不同系统实现可能不同):
sl@Li:/proc/sys/net/ipv4$ cat tcp_keepalive_time 7200 sl@Li:/proc/sys/net/ipv4$ cat tcp_keepalive_intvl 75 sl@Li:/proc/sys/net/ipv4$ cat tcp_keepalive_probes 9
TIME_WAIT(即2MSL)有什么用?弊端在哪呢?
TIME_WAIT状态之所以存在,是为了保证网络的可靠性 1.为实现TCP全双工连接的可靠释放 当服务器先关闭连接,如果不在一定时间内维护一个这样的TIME_WAIT状态,那么当被动关闭的一方的FIN到达时(应该重发ACK),服务器的TCP传输层会用RST包响应对方,这样被对方认为是有错误发生,事实上这只是正常的关闭连接工程,并没有异常。 2.为使过期的数据包在网络因过期而消失 在这条连接上,客户端发送了数据给服务器,但是在服务器没有收到数据的时候服务器就断开了连接。现在数据到了,服务器无法识别这是新连接还是上一条连接要传输的数据,一个处理不当就会导致诡异的情况发生。 弊端在哪? 在高并发短连接的TCP服务器上,当服务器处理完请求后主动请求关闭连接,这样服务器上会有大量的连接处于TIME_WAIT状态,而文件描述符的使用是有上限的,如果持续高并发,会导致一些连接失败。 还有一种情况,假设今天双十一,这是一台Tmall的服务器,因为一些原因,服务器进程挂掉了,退出了,由于是服务器主动关闭连接,因此会有TIME_WAIT状态存在,也就意味着服务器进程想立即重启,但是起不来,因为端口(可能是80)还被之前处于TIME_WAIT的连接占用着,如果TIME_WAIT状态维持60秒,60秒服务器都起不来,双十一,啧啧。 如何避免? 可设置套接字选项为SO_REUSEADDR,该选项的意思是,告诉操作系统,如果端口忙,但占用该端口TCP连接处于TIME_WAIT状态,并且套接字选项为SO_REUSEADDR,则该端口可被重用。如果TCP连接处于其他状态,**依然返回端口被占用。**该选项对服务程序重启非常有用。链接
TCP的沾包、半包问题,怎么解决呢?
粘包拆包问题在数据链路层、网络层以及传输层都有可能发生。我们日常的网络应用开发大都在传输层进行,由于UDP有消息保护边界,不会发生粘包拆包问题,因此粘包拆包问题只发生在TCP协议中。 什么是粘包、拆包(半包)? 假设客户端向服务端连续发送了两个数据包,用packet1和packet2来表示,那么服务端收到的数据可以分为三种,现列举如下:
- 第一种情况,接收端正常收到两个数据包,即没有发生拆包和粘包的现象,此种情况不在本文的讨论范围内。
- 第二种情况,接收端只收到一个数据包,由于TCP是不会出现丢包的,所以这一个数据包中包含了发送的两个数据包的信息,这种现象即为粘包。这种情况由于接收端不知道这两个数据包的界限,所以对于接收端来说很难处理。
- 第三种情况,这种情况有两种表现形式,如下图。接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包。这两种情况如果不加特殊处理,对于接收端同样是不好处理的。
详述TCP可靠性是如何保证的
校验和、确认应答和序列号、重传机制,连接管理(握手和挥手)滑动窗口流量控制,拥塞控制
- 重传机制:
1.超时重传,超过RTO(略大于RTT(往返时延,一端到另一端的时间))则重传。 如果超时后又需要重传,则策略为超时间隔加倍。两次超时,就说明网络环境差,不宜频繁反复发送。缺点为超时时间RTO不易计算。 2.快速重传,不以时间为驱动,而是以数据驱动重传。 重传没有收到的报文的ACK序列号,但未解决的问题是对端是重传所有的还是重传未收到的那一个,则又有两种机制: Sack**(Selective Acknowledgment** 选择性确认) 它可以将缓存的数据表发送给发送方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。 D-Sack**(Duplicate SACK)(常用的是这种)** 使用了SACK来告诉「发送方」有哪些数据被重复接收了。 两种的原因是有两种丢包情况 第一种接收方的ACK****报文丢失了,触发了超时重传,使发送方发送了重复的包 第二种是因为网络延迟,包在之后才到达接收方,而由于之前没有ACK,则发送方会重传,之后接收方收到后会发送DSACK,告知发送方出现了网络延迟 D-SACK 有这么几个好处:链接
- 滑动窗口:
为解决一发一回低效的传输方式,TCP引入窗口概念,窗口的大小是无需等待确认应答,而可以继续发送数据的最大值。滑动窗口采用累计确认的机制,只需要回复最后一次接收到包的ACK序号。 窗口的大小由TCP报文的Window决定,接收端告诉发送端自己有多少缓冲区可以接收,于是发送方根据接收方的处理能力来发送数据,从而不会导致接收端不会处理不过来。 接收方的窗口不一定是相等的,是约等于关系,因为滑动窗口并不是一成不变的。比如,当接收方的应用进程读取数据的速度非常快的话,这样的话接收窗口可以很快的就空缺出来。那么新的接收窗口大小,是通过 TCP 报文中的 Windows 字段来告诉发送方。那么这个传输过程是存在时延的,所以接收窗口和发送窗口是约等于的关系。
- 流量控制:
实际上,发送窗口和接收窗口中所存放的字节数,都是放在操作系统内存缓冲区中的,而操作系统的缓冲区,会被操作系统调整。如果发生了先减少缓存,再收缩窗口,就会出现丢包的现象。为了防止这种情况发生,TCP 规定是不允许同时减少缓存又收缩窗口的,而是采用先收缩窗口,过段时间在减少缓存,这样就可以避免了丢包情况。
- 窗口关闭问题:
如果窗口大小为 0 时,就会阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭。 当发生窗口关闭时,接收方处理完数据后,会向发送方通告一个窗口非 0 的 ACK 报文,如果这个通告窗口的 ACK 报文在网络中丢失了,那麻烦就大了。 为了解决这个问题,TCP 为每个连接设有一个持续定时器,只要 TCP 连接一方收到对方的零窗口通知,就启动持续计时器。如果持续计时器超时,就会发送窗口探测 ( Window probe ) 报文,而对方在确认这个探测报文时,给出自己现在的接收窗口大小。窗口探查探测的次数一般为 3此次,每次大约 30-60 秒(不同的实现可能会不一样)。如果 3 次过后接收窗口还是 0 的话,有的 TCP 实现就会发 RST 报文来中断连接。
- 糊涂窗口综合征:
如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症。 我们的 TCP + IP 头有 40 个字节,为了传输那几个字节的数据,要达上这么大的开销,这太不经济了。 发送方通常的解决策略: 使用 Nagle 算法,该算法的思路是延时处理,它满足以下两个条件中的一条才可以发送数据: 1.要等到窗口大小 >= MSS 或是数据大小 >= MSS 2.收到之前发送数据的ack回包 只要没满足上面条件中的一条,发送方一直在囤积数据,直到满足上面的发送条件。 另外,Nagle 算法默认是打开的,如果对于一些需要小数据包交互的场景的程序,比如,telnet 或 ssh 这样的交互性比较强的程序,则需要关闭 Nagle 算法。 可以在 Socket 设置 TCP_NODELAY 选项来关闭这个算法(关闭 Nagle 算法没有全局参数,需要根据每个应用自己的特点来关闭)
- 拥塞控制:
流量控制是避免发送方数据填满接收方的缓存,但并不知道整个网络环境种发送了什么。一般来说,计算机网络都处在一个共享的环境。因此也有可能会因为其他主机之间的通信使得网络拥堵。 TCP 不能忽略网络上发生的事,它被设计成一个无私的协议,当网络发送拥塞时,TCP 会自我牺牲,降低发送的数据量。 于是,就有了拥塞控制,控制的目的就是避免「发送方」的数据填满整个网络。为了在「发送方」调节所要发送数据的量,定义了一个叫做「拥塞窗口」的概念。 拥塞窗口 cwnd是发送方维护的一个的状态变量,它会根据网络的拥塞程度动态变化的。 我们在前面提到过发送窗口 swnd 和接收窗口 rwnd 是约等于的关系,那么由于入了拥塞窗口的概念后,此时发送窗口的值是swnd = min(cwnd, rwnd)。 拥塞控制算法: **1.**慢启动 **2.**拥塞避免 **3.**拥塞发生 **4.**快重传快恢复 ·慢启动:拥塞窗口从1开始指数级增长(因为收到一个ack则使窗口+1),涨到慢启动门限ssthresh(一般是65535)使启动拥塞避免算法 ·拥塞避免:窗口成线性增长,增长速率放慢,当出现3个ACK未回复,则进入拥塞发生算法 ·拥塞发生:超时重传和快速重传算法启动 1.超时重传:慢启动门限降低为现在拥塞窗口的1/2,窗口大小降低到1 2.快重传快恢复算法(避免突然降低窗口大小导致处理能力突然降低):窗口大小更新为慢启动门限+3,慢启动门限更新更新为窗口大小的1/2 https://www.cnblogs.com/xiaolincoding/p/12732052.html
什么是TCP五元组?
源/目的IP+源/目的端口+传输层协议; 这五个元素即可标识一个连接;(返回一个文件描述符)
什么是TCP fast open?
即是在建立连接的时候发送一些数据。(快速建立一个之前已经建立过的连接) https://www.cnblogs.com/Serverlessops/p/12249539.html
close_wait和TIME_wait?
如何造成,如何解决? https://www.cnblogs.com/grey-wolf/p/10936657.html https://www.cnblogs.com/dadonggg/p/8778318.html
TCP的流控和拥塞控制
http://www.52im.net/thread-515-1-1.html(讲的真清楚!)
Socket与TCP连接过程
https://www.cnblogs.com/jmcui/p/14145488.html https://www.cnblogs.com/straight/articles/7660889.html 有关已连接套接字与监听套接字解释: TCP无法仅通过目的IP和端口就实现区分,而是需要套接字的四个元素:目的和源共同作用,它们的fd是不一样的。 https://blog.csdn.net/renrenhappy/article/details/5928994
Socket与Udp编程
https://www.cnblogs.com/skyfsm/p/6287787.html
UDP
传输方式
面向报文:应用层给多少数据给UDP,UDP就直接打包发送一个报文。其报文格式如下:
那么UDP数据包(指应用层给的数据)应该多大呢? 取决于:UDP协议本身(16的报文长度~65535);数据链路层的MTU(最大传输单元);Socket的UDP发送缓冲区大小; UDP数据包=最大值-IP头-UDP头; 注:最大值根据实际考虑因素来定。发送和接收
UDP通信的有界性:发送几次就接收几次; UDP发送的无序性和非可靠性:顺序错乱或者包丢失; 如何解决? 1:给自己发的数据定义协议,序号\大小\数据。 2:传输过程都要进行双方验证,是否接受到正确的数据。根据传输的字节大小来管理的。 UDP包的分片时IP层负责的:分片丢失直接CRC校验丢弃包(FRC是存放CRC校验丢弃包); 什么原因造成丢包? IP层分片丢失,造成CRC校验不通过直接丢弃包; Socket缓冲区满; ARP缓存过期,更新期间UDP包保留有上限; 什么是冗余传输方案?
UDP比TCP真的高效?
并不一定。如今TCP协议已经高度优化,在效率方面已有很大的提升。影响UDP高效的因素: UDP发包过大或过小,都会造成带宽利用率不高(过小,头部数据占比过大;过大,需要分片,一旦丢失就白给); 无法根据拥堵情况调整发包; 改进****UDP成本较高;(UDP没有重传机制,要想实现只能从应用层改进,没有接收到UDP的包就通知客户重传); 适用的场景是? 高实时性和低持续性的场所:如****DNS查询; 多点通信;如电话会议等等; NAT****穿透的成功率更高;
UDP缓冲区
发送缓冲区?只不过是限制在UDP数据报的大小(UDP不需要重传,自然不需要保留副本); 接收缓冲区?保留接收到数据以待程序取用,UDP没有流量控制,一旦缓冲区慢就丢弃了;
用UDP实现TCP:QUIC - Quick UDP Internet Connection
QUIC是谷歌设计的一种互联网传输层协议,基于UDP传输层协议,同时兼具TCP、TLS、HTTP/2等协议的可靠性与安全性,可以有效减少连接与传输延迟,更好地应对当前传输层与应用层的挑战。此协议是一系列协议的集合,主要包括:
- 传输协议(Transport)
- 丢包检测与拥塞控制(Recovery)
- 安全传输协议(TLS)
- HTTP3协议(本文未涉及)
- HTTP头部压缩协议(本文未涉及)
- 负载均衡协议(Load Balance)
TCP + TLS + HTTP/2 = UDP + QUIC + HTTP/2API
QUIC 与现有TCP +TLS + HTTP/2 方案相比,有以下几点主要特征:
- 建立低延迟连接(1-RTT或者 0-RTT)
- 改进的拥塞控制
- 无队头阻塞的多路复用
- 前向冗余纠错机制
- 连接平滑迁移,网络状态的变更不会影响连接。
网络层
IP
IP是Internet Protocol(网际互连协议)的缩写,分为Ipv4和Ipv6。前者是32位,后者是128位。 注:IPv6可以兼容IPv4地址(存疑,查资料发现没有定论),即可以用IPv6格式表示IPv4地址。表示方式为:IPv6块值为ffff,其后面紧跟“点分四组”的格式。如:::ffff:10.0.0.1(::是全0的简写) 可以代表IPv4:10.0.0.1 Ipv4的报文如下:
- 版本:v4为4,v6为6
- 首部长度:是指IP报的首部32位的个数(便于定位数据部分),一般是5,最大为15;
- 区分服务:与Qos,传输,吞吐量等参数有关
- ECN:拥塞标识符、
当一个带有ECN标记的分组发送后,如果接收端“持续拥塞”且“具有感知****ECN的能力”(如TCP),那么接收端会通知发送端降低发送速度。
- 总长度:IP数据报的总长度,连带头部加数据部分;
- 标识:IP软件在存储器中维持一个计数器,每产生一个数据报,计数器就加1,并将此值赋给标识字段。但这并不是序号,因为IP是无连接服务,不存在按序接收。它的作用是在IP数据报大于MTU需要分片时,
- 标志:占3位,但只有2位有意义。
标志字段中的最低位记为MF(More Fragment)。MF=1即表示后面“还有分片”的数据报。MF=0****表示这已是若干数据报片中的最后一个。标志字段中间的一位记为DF(Don’t Fragment),意思是“不能分片”。只有当DF=0时才允许分片。
- 片偏移:以8字节为单位,相对于用户数据段分片的偏移;
- 生存时间:可经过路由器的数量;
- 协议:表示传输层协议类型:17UDP,6TCp;
- 首部校验和:只校验首部;
- 可选字段:
注:IP协议负责添加两个头部:MAC头部,给以太网包含MAC地址;IP头部,包含IP地址;
DNS
DNS的作用就是将IP****地址与域名间映射关系域名解析成IP地址IP地址解析成域名。基于UDP协议。 注:除了域名解析还可以用来智能DNS(就近访问服务器)、DNS轮询、负载均衡等。 其简单过程为,当一台主机需要对某个域名发送数据时,向最近的DNS服务器发送请求,DNS服务器返回获取的IP地址给该主机。 其中,客户端的请求查询消息包含三种信息: 域名:即网站名称; Class:DNS设计之初,考虑到了互联网之外的其他网络,Class就是网络的分类,如今只有互联网了,因此这个值一直为IN。 记录类型:记录域名对应何种类型,如A表示域名对应IP,MX表示域名对应邮件服务。不同的记录类型返回的信息格式也不一样。 DNS保存的对应表抽象出来就如下图所示:
不可能全球的域名解析都在一台服务器上来完成(现如今的技术无法实现这么大的访问量有良好的表现),只能采取分布式存储的方法。实际设计中,域名信息是以分层次的方式来保存的,如下图: 注:根域,用 “.” 表示,相应服务器称为根服务器,一般书写域名时经常被省略,但根域毕竟是真实存在的。二级域又称为权威域。全球共有13台DNS根服务器(大部分在美国,最近的在日本)。 由于域名分层级,就会出现当前DNS服务器找不到对应IP域名的情况,这时就需要通过查询该DNS服务器的上级DNS服务器了,此时查询方法又分为两类: 迭代查询与递归查询,前者本地DNS服务器是告诉主机一个IP地址,让它自行请求****IP地址对应的DNS服务器;后者是本地DNS服务器访问上级DNS服务器之后将结果返回主机。(一个是你去,另一个是我帮你去) 注:主机向本地DNS服务器一般是递归,本地DNS向根域是迭代; 为加快DNS域名解析的速度,引入了DNS缓存:可以记住之前查询过的域名。如果要查询的域名和相关信息已经在缓存中,那么就可以直接返回响应,接下来的查询可以从缓存的位置开始向下进行。 注:DNS劫持,把目标网站域名解析到错误的IP地址从而实现用户无法访问目标网站的目的或者蓄意或恶意要求用户访问指定IP地址(网站)的目的。ICMP
https://jishuin.proginn.com/p/763bfbd23b23 ICMP(Internet Control Message Protocol)报文是一种差错控制协议。 ICMP报文分为差错报告报文和查询报文。
- 差错报告报文报告了路由器或者主机在处理IP数据报过程遇到的问题。
- 查询报文总是成对成双出现的,主要帮助主机或者网络管理人员获取特定的信息。
常见的Ping操作其实就是发送的ICMP报文(类型字段为8),如果能够达到主机,主机回送类型字段0的报文。其他类型的字段参考上述的超链接。 ICMP协议的功能主要有:
- 确认IP包是否成功到达目标地址
- 通知在发送过程中IP包被丢弃的原因
需要注意: 1.ICMP是基于IP****协议工作的,它并不是传输层的功能,仍然把它归结为网络层协议
- ICMP只能搭配IPv4使用,如果是IPv6的情况下, 需要是用ICMPv6****。
- ICMP报文包含在IP数据报中,IP报头在ICMP报文的最前面。一个ICMP报文包括IP报头(至少20字节)、ICMP报头(至少八字节)和ICMP报文(属于ICMP报文的数据部分)。
其中,ICMP的报头格式如下:
ARP协议
ARP(Address Resolution Protocol)即地址解析协议,属于TCP/IP协议簇,用于实现从 IP 地址到 MAC 地址的映射,即询问目标IP对应的MAC地址。(主要是在路由阶段,需要不停地进行拆分和封装帧) ARP协议来获知目的主机的MAC地址,完成数据封装。ARP****请求是通过广播(CSMA/CD)传递,ARP响应则是单播传递(因为知道消息来源)。 它的一些有趣的细节:到底是链路层还是网络层、抓包分析、缓存表时间···以及常用术语如中间人拦截、内网渗透、流量欺骗、ARP攻击等, 可参考https://zhuanlan.zhihu.com/p/28771785。 它还有个兄弟,ARAP协议,用来干啥的? 原先在设计的时候,它的功能就是根据MAC****获取IP地址,功能跟DHCP是一样的(现在ARAP协议已废弃,被DHCP包含)。 例如新主机接入网络,便想局域网发送ARAP广播(MAC的形式),如果有ARAP服务器,则会给该主机分配一个IP地址。现在只有无盘工作站还在使用(无盘工作站其实就是把硬盘和主机分离,无盘工作站只执行操作不执行存储)。而后基于ARAP,有了Bootp协议,不仅获取IP还有网关。 仍然没解决问题,服务器仍然需要提前手工绑定****MAC和IP地址,而对于现在的移动网络或者公共网络而言,这根本无法实现。所以后面有了DHCP协议。
IGMP
英特网组管理协议**(Internet Group Management Protocol),主要用来实现组播扩展。 IGMP报文分为成员关系报告报文(报告给路由器)和成员关系查询报文(查询路由器信息)。 什么是组播? https://baike.baidu.com/item/%E7%BB%84%E6%92%AD/8946116?fr=aladdin 解决一发多的造成的资源多次拷贝和带宽占用的问题,一次将数据发送到一个组内的所有成员主机。**
为什么使用IP地址通信?
由于全世界存在着各式各样的网络,它们使用不同的硬件地址。要使这些异构网络能够互相通信就必须进行非常复杂的硬件地址转换工作,因此几乎是不可能的事。 连接到因特网的主机都拥有统一的 IP 地址,它们之间的通信就像连接在同一个网络上那样简单方便,因为调用 ARP 来寻找某个路由器或主机的硬件地址都是由计算机软件自动进行的,对用户来说是看不见这种调用过程的。 (而且IP子网的寻址就很简单了哈!)
IP****的三个历史阶段
一是,分类****IP,ABCDE,很快网络号就不够了。 二是,子网划分,分为网络号、子网号、主机; 三是,CIDR(无类别路由),以前必须8位为一段,现在可以任意划分;
RIP路由协议
网络中的每一个路由器都要维护从它自己到其他每一个目标网络的距离记录;距离也称为跳数,规定从一路由器到直接连接的网络跳数为1,而每经过一个路由器,则距离加1; 1、每一个路由表项目包括三个内容:目的网络、距离、下一跳路由器 2、RIP认为好的路由就是它通过的路由器数量最少; 3、RIP允许一条路径上最多有15个路由器,因为规定最大跳数为16; 4、RIP默认每30秒广播一次RIP路由更新信息。 距离向量算法 1、对地址为X的路由器发过来的路由表,先修改此路由表中的所有项目:把”下一跳”字段中的地址改为X,并把所有”距离”字段都加1。 2、对修改后的路由表中的每一个项目,进行以下步骤: 2.1、将X的路由表(修改过的),与S的路由表的目的网络进行对比。 若在X中出现,在S中没出现,则将X路由表中的这一条项目添加到S的路由表中。 2.2、对于目的网络在S和X路由表中都有的项目进行下面步骤 2.2.1、在S的路由表中,若下一跳地址是x ,则直接用X路由表中这条项目替换S路由表中的项目。 2.2.2、在S的路由表中,若下一跳地址不是x ,若X路由表项目中的距离d小于S路由表中的距离,则进行更新。 3、若3分钟还没有收到相邻路由器的更新表,则把此相邻路由器记为不可到达路由器,即把距离设置为16。
硬件设备
互联网的高速连接,除了设计精巧的各类协议之外,离不开各类硬件设备,如主机、中继器、集线器、网关、网桥、路由器、交换器、调制解调器等。 双绞线、同轴电缆、光纤、电波 电话网、电视网、光缆(光纤)、无线传输 什么是DSL、ADSL? DSL,数字用户线路,原本基于铜制电话线; ADSL,非对称···,可以基于电话线实现宽带服务;
中继器—物理层
信号在传递过程中会衰减,中继器对信号进行放大,防止因信号衰减影响通信。
集线器(HUB)—物理层
集线器的主要功能是对接收到的信号进行再生整形放大(CSMA/CD),以扩大网络的传输距离,同时把所有节点集中在以它为中心的节点上(广播)。
网桥—链路层
集线器是进行广播通信,为了防止不同子网之间通信冲突,需要进行隔离,这就是网桥的用途。
(https://blog.csdn.net/sunmeok/article/details/81157125)交换机—链路层
由于网桥只有两个端口,当AB子网中同时有多个主机间进行通信就会产生冲突。基于此,出现了交换机,交换机的存在使得各个主机可以同时通信互不影响(因为使用了不同的端口)。 注:通过ARP协议学习MAC地址,保存一张表Port-Mac
路由器—网络层
可以决定数据包从来源端到目的端所经过的路径,这个过程称为路由;将路由器输入端的数据包移送至适当的路由器输出端,这称为转送。它主要实现不同网络间的通信。 路由器到底是如何路由的?https://product.pconline.com.cn/itbk/wlbg/network/1802/10851331.html
面试常问
短网址到长网址的解析
什么是短网址到长网址的解析? https://www.zhihu.com/question/29270034/answer/46446911 相比于长链接,短链接的好处如下:
- 太长的链接容易被限制长度
- 短链接看着简洁,容易推广
- 安全,不想暴露参数
Session、Token、Cookie
HTTP是无状态协议,每次都需要去验证身份,因此,服务器希望维护一个状态来知道前后两个请求是否来自同一浏览器。https://www.cnblogs.com/moyand/p/9047978.html 参考链接
- Cookie:客户信息保存在客户手上,相当于一个优惠券
一个文本文件,其内部格式为key-value,当浏览器向服务器请求时,如果该次会话需要记录客户状态,则服务器****response一段数据,即是Cookie。当浏览器再次请求该网站时,会在请求中带上Cookie,(简单来说就是一小段凭证,免去繁琐的用户验证) 其工作机制如下:
Cookie属性项如下:- Session:客户信息保存在服务端,相当于有一个表格,你报上电话号码就可以了
当访问服务器网页的时候,会在服务器端的内存里开辟一块内存,这块内存就叫做****session,而这个内存是跟浏览器关联在一起的。只允许当前这个session对应的浏览器访问,就算是在同一个机器上新启的浏览器也是无法访问的。就是当访问一个页面的时候给浏览器创建一个独一无二的号码,也给同时创建的session赋予同样的号码(session ID)。 那么如何进行session ID的收发呢? 一是基于****Cookie,即将session ID放入Cookie中,服务器就可以进行ID验证。(浏览器不支持Cookie那就用下一种) 二是基于URL****重写,即将session ID附加在URL路径后面。 · 区别 Cookie****最大4K,session为12K,因此一旦数量过多会造成服务器极大负担。 session 是基于 cookie 实现的,它们两个主要有以下特点:
- session 比 cookie 更加安全,因为它是存在服务端的,cookie 是存在客户端的。
- cookie 只支持存储字符串数据,session 可以存储任意数据。
- cookie 的有效期可以设置较长时间,session 有效期都比较短。
- session 存储空间很大,cookie 有限制。
- Token
适用于项目级的前后端分离(前后端代码运行在不同的服务器下)。 Token令牌:客户端A访问服务器,服务器给了客户端token,客户端A拿着token访问服务器,服务器验证token,返回数据。 Token的作用就是生成一个令牌,其中包含userid,而后对该令牌进行数据签名(密钥只有服务器知晓)。服务器不需要保存Token,只需要在客户端发送过来之后对该Token进行解密,如果不一致则说明token被修改,验证不通过。这样就减少了保存session所需要的内存空间。 Token生成的: 前面我们说 cookie 是服务端设置了 set-cookie 响应头之后,浏览器会自动保存 cookie,然后下一次发送请求的时候会自动把 cookie 携带上。但是我们说 cookie 算是一种民间的实现方式,所以说浏览器自然不会对它进行成么处理。token 主要是由服务器生成,然后返回给客户端,客户端手动把 token 存下来,比如利用 localstorage 或者直接存到 cookie 当中也行。 token 认证流程:
- 客户端发起登录请求,比如用户输入用户名和密码后登录。
- 服务端校验用户名和密码后,将用户 id 和一些其它信息进行加密,生成 token。
- 服务端将 token 响应给客户端。
- 客户端收到响应后将 token 存储下来。
- 下一次发送请求后需要将 token 携带上,比如放在请求头中或者其它地方。
- 服务端 token 后校验,校验通过则正常返回数据。
优点:1.安全,因为 token 一般只有用户 id,就算被截取了也没什么用。无法解密。2.无需消耗服务器内存资源,它相当于只存了用户 id,session 相当于存储了用户的所有信息。3.跨域处理较为方便,比如多台服务器之间可以共用一个 token。 缺点:时间换空间 Token: https://blog.csdn.net/qq_36262295/article/details/116565331
Session如何保证负载均衡到同一用户的?
如果负载均衡,客户端A访问了另一个服务器,那个服务器没有客户端A的数据。 Session共享有四种方法,分别是:1、基于数据库的Session共享;2、基于Cookie的Session共享;3、基于Memcache的Session共享。 1. 基于数据库的Session共享 首选当然是大名鼎鼎的Mysql数据库,并且建议使用内存表Heap,提高session操作的读写效率。这个方案的实用性比较强,相信大家普 遍在 使用,它的缺点在于session的并发读写能力取决于Mysql数据库的性能,同时需要自己实现session淘汰逻辑,以便定时从数据表中更新、删除 session记录,当并发过高时容易出现表锁,虽然我们可以选择行级锁的表引擎,但不得不否认使用数据库存储Session还是有些杀鸡用牛刀的架势。 2. 基于Cookie的Session共享 这个方案我们可能比较陌生,但它在大型网站中还是比较普遍被使用。原理是将全站用户的Session信息加密、序列化后以Cookie的方式, 统一 种植在根域名下(如:.host.com),利用浏览器访问该根域名下的所有二级域名站点时,会传递与之域名对应的所有Cookie内容的特性,从而实现 用户的Cookie化Session 在多服务间的共享访问。 这个方案的优点无需额外的服务器资源;缺点是由于受http协议头信心长度的限制,仅能够存储小部分的用户信息,同时Cookie化的 Session内容需要进行安全加解密(如:采用DES、RSA等进行明文加解密;再由MD5、SHA-1等算法进行防伪认证),另外它也会占用一定的带 宽资源,因为浏览器会在请求当前域名下任何资源时将本地Cookie附加在http头中传递到服务器。 3. 基于Memcache、Redis的Session共享 简单的Key + Value数据存储模式使得代码逻辑小巧高效,因此在并发处理能力上占据了绝对优势,目前本人所经历的项目达到2000/秒 平均查询,并且服务器CPU消耗依然不到10%。另外值得一提的是Memcache的内存hash表所特有的Expires数据过期淘汰机制,正好和Session的过期机制不谋而合,降低了 过期Session数据删除的代码复杂度,对比“基于数据库的存储方案”,仅这块逻辑就给数据表产生巨大的查询压力。
从输入URL到页面展示到底发生了什么?
https://blog.csdn.net/xiamiflying/article/details/81477539 输入地址;(目的地) 查询DNS服务器;(目的地归一化) 发起TCP连接请求;(获取通关碟文) 发起HTTP请求;(说明来意) (301/302重定向,为了网站的排名) 获取HTTP响应;(接收快递) 显示HTML文档;(打开快递包) 继续发起HTTP请求;(资源有缺漏) 或是答: 一般会经历以下几个过程: 1、首先,在浏览器地址栏中输入url 2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容,若没有则, 3、需要域名解析(DNS解析),解析获取相应的IP地址。 4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。 5、握手成功后,浏览器向服务器发送http请求,请求数据包。 6、服务器处理收到的请求,将数据返回至浏览器 7、浏览器收到HTTP响应 8、读取页面内容,浏览器渲染,解析html源码
负载均衡了解吗?
解决如何将不同的用户的流量分发到不同的服务器上面呢? 早期的方法是使用DNS做负载,通过给客户端解析不同的IP地址,让客户端的流量直接到达各个服务器。但是这种方法有一个很大的缺点就是延时性问题,在做出调度策略改变以后,由于DNS各级节点的缓存并不会及时的在客户端生效,而且DNS负载的调度策略比较简单,无法满足业务需求,因此就出现了负载均衡。 客户端的流量首先会到达负载均衡服务器,由负载均衡服务器通过一定的调度算法将流量分发到不同的应用服务器上面,同时负载均衡服务器也会对应用服务器做周期性的健康检查,当发现故障节点时便动态的将节点从应用服务器集群中剔除,以此来保证应用的高可用。 负载均衡又分为四层****负载均衡和七层负载均衡。 四层负载均衡工作在OSI模型的传输层,主要工作是转发,它在接收到客户端的流量以后通过修改数据包的地址信息将流量转发到应用服务器。 七层负载均衡工作在OSI模型的应用层,因为它需要解析应用层流量,所以七层负载均衡在接到客户端的流量以后,还需要一个完整的TCP/IP协议栈。七层负载均衡会与客户端建立一条完整的连接并将应用层的请求流量解析出来,再按照调度算法选择一个应用服务器,并与应用服务器建立另外一条连接将请求发送过去,因此七层负载均衡的主要工作就是代理。 负载均衡的算法?
- 随机算法;2、轮询及加权轮询;3、最小连接及加权最小连接;4、哈希算法;5、IP地址散列6、URL散列;
路由的原理?
为了理解路由表中的信息种类,我们需要先考虑数据包到达路由器接口时会发生什么,这是非常有用的。 首先,路由器会检查数据帧目标地址字段中的数据链路标识。如果它包含了路由器接口标识符或广播标识符,那么路由器将从帧中剥离出数据包并传递给网络层。 (路由器横跨链路层和网络层)在网络层,路由器将检查数据包的目标地址。如果目标地址是路由器接口的IP地址或是所有主机的广播地址,交给路由器内部处理。 除此之外,所有其他目标地址都需要进行路由选择。 这里的目标地址可能是另一个网络上的主机地址,该网络或者与路由器相连(包括与那个网络相连接的路由器接口),或者不直接连接到路由器上目标地址还可能是一个定向的广播地址,这种地址有明确的网络地址或子网地址并且主机位全部为1。 路由器将会尽量地进行最精确的匹配。按精确程度递减的顺序,可选地址排列如下:
- 主机地址(主机路径) ;
- 子网:
- 一组子网(一条汇总路由) :
- 主网号:
- 一组主网号(超网) ;
- 缺省地址(另外的网关)
如果数据包的目标地址不能匹配到任何一条路由表项,那么数据包将被丢弃,同时一个“目标网络不可达"的ICMP消息将会被发送给源地址。
路由表的信息及结构?
路由表中的表项内容包括: destination:目的地址,用来标识IP包的目的地址或者目的网络。 mask:网络掩码,与目的地址一起标识目的主机或者路由器所在的网段的地址。 pre:标识路由加入IP路由表的优先级。可能到达一个目的地有多条路由,但是优先级的存在让他们先选择优先级高的路由进行利用。 cost:路由开销,当到达一个目的地的多个路由优先级相同时,路由开销最小的将成为最优路由。 interface:输出接口,说明IP包将从该路由器哪个接口转发。 nexthop:下一跳IP地址,说明IP包所经过的下一个路由器。 路由表在少量时可以使用hash表来存储,但是当数据量大的时候,就需要使用trie树来存储了,比较稳定链接 常见路由协议:RIP、OSPF(开放式最短路径优先)链接
QQ微信是什么协议呢?
https://blog.csdn.net/weixin_43788290/article/details/105895983
什么是Dos攻击?
DoS是Denial of Service的简称,即拒绝服务。 常见攻击如TCP syn泛洪、ping泛洪、UDP泛洪(UDP无连接,防不胜防,只能禁用一些端口)、 https://blog.csdn.net/qq_29344757/article/details/86658936
URI、URL、URN
https://www.cnblogs.com/yplong/p/5572033.html URI:Uniform Resource Identifier,即统一资源标志符,用来唯一的标识一个资源。 URL:Uniform Resource Locator,统一资源定位符。即URL可以用来标识一个资源,而且还指明了如何locate这个资源。 URN:Uniform Resource Name,统一资源命名。即通过名字来表示资源的。 URL肯定是一个URI,但是一个URI并不一定是一个URL,URL仅仅是URI的一种表现形式而已。 两者的差距主要可以从命名上来区分,URI是资源标志符,所有他只要求具有"标识性",而URL是和URI的主要区别就是,URL除了具有URI的“标识性”以外,还具有定位功能,可以用来描述资源的具体位置,还指明了获取资源所采用的协议。 一个完整的URL包含协议名称,主机名称(IP或者域名)、端口号(没写端口号默认 为80端口)、路径和查询字符串这5个部分。比如:http://www.microsoft.com:80/images/hello.png?type=png.这样一个url,上述的5个部分分别是:网络传输协议名称:http,主机:www.mcrosoft.com,端口号:80,路径:images/hello.png 查询字符串:type=png。 看完了URL和URI的区别,我们在看看URN是什么东西。URN也是URL的一种表现形式,它和URL的区别就是与资源的位置无关,由于位置的无关性,被某个URN标识的资源在位置发生变化时,其URI可以保持不变。 所以看来URL和URN都是URI的一种扩展,一种表现形式,URL和URN肯定是一个URI,但是URI不一定是URN或URL。