计算机网络2 | 青训营笔记

94 阅读56分钟

数据结构与算法 | 青训营笔记

这是我参与「第四届青训营 」笔记创作活动的第13天

5、DNS

域名系统DNS(Domain Name System)是互联网使用的命名系统,用来把便于人们使用的机器名字转换为IP地址,这个过程叫做DNS域名解析。

zhuanlan.zhihu.com/p/79350395

DNS域名解析流程图

如图所示,大致就是:浏览器输入地址,然后浏览器这个进程去调操作系统某个库里的gethostbyname函数(例如,Linux GNU glibc标准库的gethostbyname函数),然后呢这个函数通过网卡给DNS服务器发UDP请求,接收结果,然后将结果给返回给浏览器。

这张图其实已经讲明白大致的流程,但是细节上可能有些差异。 例如

  • (1)我们在用chrome浏览器的时候,其实会先去浏览器的dns缓存里头查询,dns缓存中没有,再去调用gethostbyname函数
  • (2)gethostbyname函数在试图进行DNS解析之前首先检查域名是否在本地 Hosts 里,如果没找到再去DNS服务器上查

此时涉及两个知识点

1、说说UDP协议在哪里使用,TCP协议在哪里使用?

TCP协议是基于连接的可靠协议,有流量控制和差错控制,也正因为有可靠性的保证和控制手段,所以传输效率比UDP低; UDP协议是基于无连接的不可靠协议,没有控制手段,仅仅是将数据发送给对方,因此效率比TCP要高。 基于上述特性,不难得到结论,TCP协议适用于对效率要求相对低,但对准确性要求相对高的场景下,或者是有一种连接概念的场景下; 而UDP协议适用于对效率要求相对高,对准确性要求相对低的场景。

2、DNS在域名解析上用UDP还是TCP?

域名解析的时候使用的是UDP

客户端向DNS服务器查询域名,一般返回的内容都不超过512字节,用UDP传输即可。不用经过三次握手,这样DNS服务器负载更低,响应更快。理论上说,客户端也可以指定向DNS服务器查询时用TCP,但事实上,很多DNS服务器进行配置的时候,仅支持UDP查询包。

需要补充说明一下,DNS中也有一个地方用到了TCP协议,那就是区域传输

1.辅域名服务器会定时(一般3小时)向主域名服务器进行查询以便了解数据是否有变动。如有变动,会执行一次区域传送,进行数据同步。区域传送使用TCP而不是UDP,因为数据同步传送的数据量比一个请求应答的数据量要多得多。

2.TCP是一种可靠连接,保证了数据的准确性。

DNS的规范规定了2种类型的DNS服务器,一个叫主DNS服务器,一个叫辅助DNS服务器。在一个区中主DNS服务器从自己本机的数据文件中读取该区的DNS数据信息,而辅助DNS服务器则从区的主DNS服务器中读取该区的DNS数据信息。当一个辅助DNS服务器启动时,它需要与主DNS服务器通信,并加载数据信息,这就叫做区传送(zone transfer)。 这种情况下,使用TCP协议。

讲到这里,面试官有可能继续追问

1、讲讲域名解析为什么要用UDP?

因为UDP快啊!UDP的DNS协议只要一个请求、一个应答就好了。而使用基于TCP的DNS协议要三次握手、发送数据以及应答、四次挥手。 但是UDP协议传输内容不能超过512字节。不过客户端向DNS服务器查询域名,一般返回的内容都不超过512字节,用UDP传输即可。

2、讲讲区域复制为什么要用TCP?

因为TCP协议可靠性好啊!你要从主DNS上复制内容啊,你用不可靠的UDP? 因为TCP协议传输的内容大啊,你用最大只能传512字节的UDP协议? 万一同步的数据大于512字节,你怎么办?

DNS域名解析的原理

先介绍Linux的dig命令,以显示域名解析的过程。为了方便说明,我们先来dig一下天猫的过程

dig www.tmall.com

结果如下图所示

第一段代表请求参数如下图所示

这段为查询内容。DNS的查询参数一般有三个

  1. 域名:服务器、邮件服务器(@后面的部分)的名称
  2. Class:在设置DNS方案时,互联网之外的网络也考虑到了,而Class就是用来识别网络的,不过现在只有互联网,所以它的值永远都是代表互联网的IN
  3. 记录类型:表示域名对应何种类型的记录。类型为A,表示域名对应的IP地址。类型为MX时,表示域名对应的是邮件服务器。类型为PTR,表示根据IP地址反查域名。类型为CNAME,表示查询域名相关别名

但是为什么输入的是tmall.com,返回的确实www.tmall.com.呢?也就是:DNS是怎么做域名解析的

www.tmall.com对应的真正域名为www.tmall.com. 末尾的.称为根域名,因为每个域名都有根域名,所以我们通常省略 根域名的下一级叫做“顶级域名”,比如“.com、 .net” 再下一级叫做“次级域名”,比如www.tmall.com里面的.tmall,这一级域名是用户可以注册的; 再下一级是主机名(host),比如www.tmall.com里面的www,又称为"三级域名",这是用户在自己的域里面为服务器分配的名称,是用户可以任意分配的。

那么解析的流程就是分级查询

(1)先在本机的DNS里头查,如果有就直接返回了。本机DNS类似下图

(2)本机DNS里头发现没有,就去根服务器里查。根服务器发现这个域名是属于com域,因此根域DNS服务器会返回它所管理的com域中的DNS 服务器的IP地址,意思是“虽然我不知道你要查的那个域名的地址,但你可以去com域问问看”

(3)本机的DNS接到又会向com域的DNS服务器发送查询消息。com 域中也没有www.tmall.com这个域名的信息,和刚才一样,com域服务器会返回它下面的tmall.com域的DNS服务器的IP地址。

以此类推,只要重复前面的步骤,就可以顺藤摸瓜找到目标DNS服务器

来看第二段内容,也就是响应体的部分! 如下所示

很明显,第一行就是说www.tmall.com有一个别名是www.tmall.com.danuoyi.tbcache.com。后面几行就是这www.tmall.com.danuoyi.tbcache.com地址的真实IP。

DNS过程

  1. 浏览器先检查自身缓存中有没有被解析过的这个域名对应的IP地址,如果有,解析结束
  2. 如果浏览器缓存中没有,浏览器会检查操作系统缓存中有没有对应的已经解析过的结果(一般会存在C盘中的一个hosts的文件中)
  3. 如果至此还没有命中域名,才会真正的请求本地域名服务器来解析这个域名,这台服务器一般在你的城市的某个角落,距离你不会很远,并且这台服务器的性能都很好,一般都会缓存域名解析结果,大约80%的域名解析到这里就完成了。
  4. 如果本地域名服务任然没有命中,就直接去访问Root Server根域名服务器请求解析
  5. 根域名服务器返回给本地域名服务器一个所查询域的主域名服务器——顶级域名服务器(gTLD Server,国际顶尖域名服务器,如.com .cn .org等)地址
  6. 此时本地域名服务器再向上进一步请求gTLD顶级域名服务器
  7. 接受请求的gTLD顶级域名服务器查找并返回这个域名对应的Name Server的地址,这个Name Server就是网站注册的域名服务器
  8. Name Server根据映射关系表找到目标ip,返回给本地域名服务器
  9. 本地域名服务器缓存这个域名和对应的ip
  10. 本地域名服务器把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束

DNS负载均衡

DNS(Domain Name System)是因特网的一项服务,它作为域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网。人们在通过浏览器访问网站时只需要记住网站的域名即可,而不需要记住那些不太容易理解的IP地址。在DNS系统中有一个比较重要的的资源类型叫做主机记录也称为A记录,A记录是用于名称解析的重要记录,它将特定的主机名映射到对应主机的IP地址上。如果你有一个自己的域名,那么要想别人能访问到你的网站,你需要到特定的DNS解析服务商的服务器上填写A记录,过一段时间后,别人就能通过你的域名访问你的网站了。DNS除了能解析域名之外还具有负载均衡的功能,下面是利用DNS工作原理处理负载均衡的工作原理图:

由上图可以看出,在DNS服务器中应该配置了多个A记录,如:

因此,每次域名解析请求都会根据对应的负载均衡算法计算出一个不同的IP地址并返回,这样A记录中配置多个服务器就可以构成一个集群,并可以实现负载均衡。上图中,用户请求www.apusapp.com,DNS根据A记录和负载均衡算法计算得到一个IP地址114.100.20.203,并返回给浏览器,浏览器根据该IP地址,访问真实的物理服务器114.100.20.203。所有这些操作对用户来说都是透明的,用户可能只知道www.apusapp.com这个域名。

DNS域名解析负载均衡有如下优点:

  1. 将负载均衡的工作交给DNS,省去了网站管理维护负载均衡服务器的麻烦。
  2. 技术实现比较灵活、方便,简单易行,成本低,使用于大多数TCP/IP应用。
  3. 对于部署在服务器上的应用来说不需要进行任何的代码修改即可实现不同机器上的应用访问。
  4. 服务器可以位于互联网的任意位置。
  5. 同时许多DNS还支持基于地理位置的域名解析,即会将域名解析成距离用户地理最近的一个服务器地址,这样就可以加速用户访问,改善性能。

同时,DNS域名解析也存在如下缺点:

  1. 目前的DNS是多级解析的,每一级DNS都可能缓存A记录,当某台服务器下线之后,即使修改了A记录,要使其生效也需要较长的时间,这段时间,DNS任然会将域名解析到已下线的服务器上,最终导致用户访问失败。
  2. 不能够按服务器的处理能力来分配负载。DNS负载均衡采用的是简单的轮询算法,不能区分服务器之间的差异,不能反映服务器当前运行状态,所以其的负载均衡效果并不是太好。
  3. 可能会造成额外的网络问题。为了使本DNS服务器和其他DNS服务器及时交互,保证DNS数据及时更新,使地址能随机分配,一般都要将DNS的刷新时间设置的较小,但太小将会使DNS流量大增造成额外的网络问题。

事实上,大型网站总是部分使用DNS域名解析,利用域名解析作为第一级负载均衡手段,即域名解析得到的一组服务器并不是实际提供服务的物理服务器,而是同样提供负载均衡服务器的内部服务器,这组内部负载均衡服务器再进行负载均衡,请请求发到真实的服务器上,最终完成请求。

6、HTTP的过程/浏览器输入一个url之后的过程

  1. 根据域名,进行DNS域名解析
  2. 拿到解析的IP地址,建立TCP连接
  3. 向IP地址发送HTTP请求
  4. 服务器处理请求
  5. 返回响应结果
  6. 关闭TCP连接
  7. 浏览器解析HTML
  8. 浏览器布局渲染

7、POST与GET的区别

最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数。

基本的区别

  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • GET产生的URL地址可以被Bookmark,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行url编码,而POST支持多种编码方式。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET请求在URL中传送的参数是有长度限制的,而POST没有。
  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • GET参数通过URL传递,POST放在Request body中。
  • GET操作具有幂等性,POST操作不具备幂等性(但是put具有幂等性)

HTTP GET方法用于获取资源,不应有副作用,所以是幂等的。 比如:GET www.bank.com/account/123…,不会改变资源的状态,不论调用一次还是N次都没有副作用。请注意,这里强调的是一次和N次具有相同的副作用,而不是每次GET的结果相同。GET www.news.com/latest-news这个HTTP请求可能会每次得到不同的结果,但它本身并没有产生任何副作用,因而是满足幂等性的。

HTTP POST方法用于创建资源,所对应的URI并非创建的资源本身,而是去执行创建动作的操作者,有副作用,不满足幂等性。 比如:POST www.forum.com/articles的语义是在www.forum.com/articles下创建一篇帖子,HTTP响应中应包含帖子的创建状态以及帖子的URI。两次相同的POST请求会在服务器端创建两份资源,它们具有不同的URI;所以,POST方法不具备幂等性。

8、都有哪些常见的请求头

http请求是指从客户端到服务器端的请求消息。包括:消息首行中,对资源的请求方法、资源的标识符及使用的协议。

http请求中的常用头(请求头)的含义:

Accept:告诉服务器,客户端支持的数据类型。

Accept-Charset:告诉服务器,客户端采用的编码。

Accept-Encoding:告诉服务器,客户机支持的数据压缩格式。

Accept-Language:告诉服务器,客户机的语言环境。

Host:客户机通过这个头告诉服务器,想访问的主机名。

If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间。

Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的。(一般用于防盗链)

User-Agent:客户机通过这个头告诉服务器,客户机的软件环境。

Cookie:客户机通过这个头告诉服务器,可以向服务器带数据。

Cookie是临时文件的意思,保存你浏览网页的痕迹,使得再次上同一页面的时候提高网速,判断你是否登录过这个网站,有些可以帮你自动登录的。

Cookie就是服务器暂存放在你的电脑里的资料(.txt格式的文本文件),通过在HTTP传输中的状态好让服务器用来辨认你的计算机。当你在浏览网站的时候,Web服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文字或是一些选择都记录下来。当下次你再访问同一个网站,Web服务器会先看看有没有它上次留下的Cookie资料,有的话,就会依据Cookie里的内容来判断使用者,送出特定的网页内容给你。

Connection:客户机通过这个头告诉服务器,请求完后是关闭还是保持链接。

Date:客户机通过这个头告诉服务器,客户机当前请求时间。

http请求中常用的响应头的含义:

Location:这个头配合302状态码使用,告诉用户端找谁。

Server:服务器通过这个头,告诉浏览器服务器的类型

Content-Encoding:服务器通过这个头,告诉浏览器数据采用的压缩格式。

Content-Length:服务器通过这个头,告诉浏览器回送数据的长度。

Content-Language:服务器通过这个头,告诉服务器的语言环境。

Content-Type:服务器通过这个头,回送数据的类型

Last-Modified:服务器通过这个头,告诉浏览器当前资源的缓存时间。

Refresh:服务器通过这个头,告诉浏览器隔多长时间刷新一次。

Content-Disposition:服务器通过这个头,告诉浏览器以下载的方式打开数据。

Transfer-Encoding:服务器通过这个头,告诉浏览器数据的传送格式。

ETag:与缓存相关的头。

Expires:服务器通过这个头,告诉浏览器把回送的数据缓存多长时间。-1或0不缓存。

Cache-Control和Pragma:服务器通过这个头,也可以控制浏览器不缓存数据。

Connection:服务器通过这个头,响应完是保持链接还是关闭链接。

Date:告诉客户机,返回响应的时间。

9、CDN

baijiahao.baidu.com/s?id=163394…

CDN实现原理

在描述CDN的实现原理,让我们先看传统的未加缓存服务的访问过程,以便了解CDN缓存访问方式与未加缓存访问方式的差别:

用户提交域名→浏览器对域名进行解析→得到目的主机的IP地址→根据IP地址访问发出请求→得到请求数据并回复

由上可见,用户访问未使用CDN缓存网站的过程为:

  • 用户向浏览器提供要访问的域名;
  • 浏览器调用域名解析函数库对域名进行解析,以得到此域名对应的IP地址;
  • 浏览器使用所得到的IP地址,向域名的服务主机发出数据访问请求;
  • 浏览器根据域名主机返回的数据显示网页的内容。

通过以上四个步骤,浏览器完成从用户处接收用户要访问的域名到从域名服务主机处获取数据的整个过程。

CDN网络是在用户和服务器之间增加Cache层,如何将用户的请求引导到Cache上获得源服务器的数据,主要是通过接管DNS实现,下面让我们看看访问使用CDN缓存后的网站的过程:

通过上图,我们可以了解到,使用了CDN缓存后的网站的访问过程变为:

1)、用户向浏览器提供要访问的域名;

2)、浏览器调用域名解析库对域名进行解析,由于CDN对域名解析过程进行了调整,所以解析函数库一般得到的是该域名对应的CNAME记录,为了得到实际IP地址,浏览器需要再次对获得的CNAME域名进行解析以得到实际的IP地址;在此过程中,使用的全局负载均衡DNS解析,如根据地理位置信息解析对应的IP地址,使得用户能就近访问。

3)、此次解析得到CDN缓存服务器的IP地址,浏览器在得到实际的IP地址以后,向缓存服务器发出访问请求;

4)、缓存服务器根据浏览器提供的要访问的域名,通过Cache内部专用DNS解析得到此域名的实际IP地址,再由缓存服务器向此实际IP地址提交访问请求;

5)、缓存服务器从实际IP地址得得到内容以后,一方面在本地进行保存,以备以后使用,另一方面把获取的数据返回给客户端,完成数据服务过程;

6)、客户端得到由缓存服务器返回的数据以后显示出来并完成整个浏览的数据请求过程。

CDN一般包含分发服务系统、负载均衡系统和管理系统

分发服务系统

其基本的工作单元就是各个cache服务器。负责直接响应用户请求,将内容快速分发到用户;同时该负责内容更新,保证和源站内容的同步。

根据内容类型和服务种类的不同,分发服务系统分为多个子服务系统,如:网页加速服务、流媒体加速服务、应用加速服务等。每个子服务系统都是一个分布式的服务集群,由功能类似、地域接近的分布部署的 Cache 集群组成。

在承担内容同步、更新和响应用户请求之外,分发服务系统还需要向上层的管理调度系统反馈各个 Cache 设备的健康状况、响应情况、内容缓存状况等,以便管理调度系统能够根据设定的策略决定由 哪个 Cache 设备来响应用户的请求。

负载均衡系统

负载均衡系统是整个 CDN 系统的中枢。负责对所有的用户请求进行调度,确定提供给用户的最终访问 地址。

使用分级实现。最基本的两极调度体系包括全局负载均衡(GSLB)和本地负载均衡(SLB)。 GSLB 根据用户地址和用户请求的内容,主要根据就近性原则,确定向用户服务的节点。一般通过 DNS 解析或者应用层重定向(Http 3XX 重定向)的方式实现。

SLB 主要负责节点内部的负载均衡。当用户请求从 GSLB 调度到 SLB 时,SLB 会根据节点内各个 Cache 设备的工作状况和内容分布情况等对用户请求重定向。SLB 的实现有四层调度(LVS)、七层调 度(Nginx)和链路负载调度等。

管理系统

分为运营管理和网络管理子系统。

网络管理系统实现对 CDN 系统的设备管理、拓扑管理、链路监控和故障管理,为管理员提供对全网资 源的可视化的集中管理,通常用 web 方式实现。

运营管理是对 CDN 系统的业务管理,负责处理业务层面的与外界系统交互所必须的一些收集、整理、 交付工作。包括用户管理、产品管理、计费管理、统计分析等。

CDN网络具体实现过程

通过以上的分析我们可以得到,为了实现既要对普通用户透明(即加入缓存以后用户客户端无需进行任何设置,直接使用被加速网站原有的域名即可访问,又要在为指定的网站提供加速服务的同时降低对ICP的影响,只要修改整个访问过程中的域名解析部分,以实现透明的加速服务,下面是CDN网络实现的具体操作过程。

1)、作为ICP,只需要把域名解释权交给CDN运营商,其他方面不需要进行任何的修改;操作时,ICP修改自己域名的解析记录,一般用cname方式指向CDN网络Cache服务器的地址。

2)、作为CDN运营商,首先需要为ICP的域名提供公开的解析,为了实现sortlist,一般是把ICP的域名解释结果指向一个CNAME记录;

3)、当需要进行sortlist时,CDN运营商可以利用DNS对CNAME指向的域名解析过程进行特殊处理,使DNS服务器在接收到客户端请求时可以根据客户端的IP地址,返回相同域名的不同IP地址;

4)、由于从cname获得的IP地址,并且带有hostname信息,请求到达Cache之后,Cache必须知道源服务器的IP地址,所以在CDN运营商内部维护一个内部DNS服务器,用于解释用户所访问的域名的真实IP地址;

5)、在维护内部DNS服务器时,还需要维护一台授权服务器,控制哪些域名可以进行缓存,而哪些又不进行缓存,以免发生开放代理的情况。

商用CDN系统

分为运营管理和网络管理子系统。

网络管理系统实现对 CDN 系统的设备管理、拓扑管理、链路监控和故障管理,为管理员提供对全网资 源的可视化的集中管理,通常用 web 方式实现。

运营管理是对 CDN 系统的业务管理,负责处理业务层面的与外界系统交互所必须的一些收集、整理、 交付工作。包括用户管理、产品管理、计费管理、统计分析等。

10、TCP与UDP

TCP基础

当一台计算机想要与另一台计算机通讯时,两台计算机之间的通信需要畅通且可靠,这样才能保证正确收发数据。例如,当你想查看网页或查看电子邮件时,希望完整且按顺序查看网页,而不丢失任何内容。当你下载文件时,希望获得的是完整的文件,而不仅仅是文件的一部分,因为如果数据丢失或乱序,都不是你希望得到的结果,于是就用到了TCP。

TCP协议全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的RFC 793定义。TCP 是面向连接的、可靠的流协议。流就是指不间断的数据结构,你可以把它想象成排水管中的水流。

TCP协议的特点

  • 面向连接

    面向连接,是指发送数据之前必须在两端建立连接。建立连接的方法是“三次握手”,这样能建立可靠的连接。建立连接,是为数据的可靠传输打下了基础。

  • 仅支持单播传输

    每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。

  • 面向字节流

    TCP不像UDP一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。

  • 可靠传输

    对于可靠传输,判断丢包,误码靠的是TCP的段编号以及确认号。TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。

  • 提供拥塞控制

    当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞

  • TCP提供全双工通信

    TCP允许通信双方的应用程序在任何时候都能发送数据,因为TCP连接的两端都设有缓存,用来临时存放双向通信的数据。当然,TCP可以立即发送一个数据段,也可以缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于MSS)

TCP的结构

img

TCP的分用功能是通过端口号实现的

序号占4个字节,所以范围是[0,2^32-1],共2的32次方个序号,需要增加到头后便返回0

确认号是期望收到对方下一个报文段的第一个数据字节的序号

若确认号=N,则表明,到序号N-1为止的所有数据都已正确收到

URG—为1表示高优先级数据包,紧急指针字段有效。
ACK—为1表示确认号字段有效
PSH—为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。
RST—为1表示出现严重差错。可能需要重现创建TCP连接。还可以用于拒绝非法的报文段和拒绝连接请求。
SYN—为1表示这是连接请求或是连接接受请求,用于创建连接和使顺序号同步
FIN—为1表示发送方没有数据要传输了,要求释放连接。

UDP基础

UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。

它有以下几个特点:

1. 面向无连接

首先 UDP 是不需要和 TCP一样在发送数据前进行三次握手建立连接的,想发数据就可以开始发送了。并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。

具体来说就是:

  • 在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了
  • 在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作

2. 有单播,多播,广播的功能

UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。

3. UDP是面向报文的

发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文

4. 不可靠性

首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。

并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。

再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。

5. 头部开销小,传输数据报文时是很高效的。

UDP 头部包含了以下几个数据:

  • 两个十六位的端口号,分别为源端口(可选字段)和目标端口
  • 整个数据报文的长度
  • 整个数据报文的检验和(IPv4 可选 字段),该字段用于发现头部信息和数据中的错误

因此 UDP 的头部开销小,只有八字节,相比 TCP 的至少二十字节要少得多,在传输数据报文时是很高效的

UDP结构

TCP与UDP的区别与可靠性

TCP是面向连接的;UDP是无连接的,即发送数据之前不需要建立连接

TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付

UDP具有较好的实时性,工作效率比TCP高,适用于对告诉传输和实时性有较高的通信或广播通信

每一条TCP连接只能是点对点的;UDP支持一对一,一对多,多对一和多对多的交互通信

TCP对资源要求较多,UDP对系统资源要求较少

TCP的首部开销为最少20字节,最大60字节,而UDP首部开销仅8字节

如何实现UDP的可靠传输

自定义通讯协议,在应用层定义一些可靠的协议,比如检测包的顺序,重复包等问题,如果没有收到对方的ACK,重新发包

UDP没有Delievery Garuantee,也没有顺序保证,所以如果你要求你的数据发送与接受既要高效,又要保证有序,收包确认等,你就需要在UDP协议上构建自己的协议。比如RTCP,RTP协议就是在UPD协议之上专门为H.323协议簇上的IP电话设计的一种介于传输层和应用层之间的协议。

UDP构建可靠数据传输

简单来讲,要使用UDP来构建可靠的面向连接的数据传输,就要实现类似于TCP协议的超时重传,有序接受,应答确认,滑动窗口流量控制等机制,等于说要在传输层的上一层(或者直接在应用层)实现TCP协议的可靠数据传输机制,比如使用UDP数据包+序列号,UDP数据包+时间戳等方法,在服务器端进行应答确认机制,这样就会保证不可靠的UDP协议进行可靠的数据传输,不过这好像也是一个难题!

目前有如下开源程序利用UDP实现了可靠的数据传输。分别为RUDP、RTP、UDT

发送方发送频率过高倒置丢包,TCP是如何解决的

TCP是基于不可靠的网络来实现可靠的传输,肯定也会存在掉包的情况,如果通信中发现缺少数据或者丢包,那么最大的可能在于程序发送的过程或者接受的过程出现问题

例如服务端要给客户端发送大量数据,send频率很高,那么就很有可能在send环节出现错误(1.程序处理逻辑错误,2.多线程同步错误,3.缓冲区溢出等),如果没有对send发送失败做处理,那么客户端收到的数据比理论要收到的数据少,就会造成丢失数据,丢包现象

常用的解决方法有:拆包、加包头、发送组合包

TCP粘包和拆包问题:

TCP是一个“流”协议,一个完整的包可能被TCP拆分成多个包发送,也有可能把小的封装成大的发送。

假设客户端分别发送数据包D1和D2给服务端,由于服务端一次性读取到的字节数是不确定的,所以可能存在以下4种情况。

1.服务端分2次读取到了两个独立的包,分别是D1,D2,没有粘包和拆包;

2.服务端一次性接收了两个包,D1和D2粘在一起了,被成为TCP粘包;

3.服务端分2次读取到了两个数据包,第一次读取到了完整的D1和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为拆包;

4.如果此时服务端TCP接收滑动窗口非常小,而数据包D1和D2都很大,很有可能发送第五种可能,即服务端多次才能把D1和D2接收完全,期间多次发生拆包情况。

接收滑动窗口:所谓滑动窗口协议,自己理解有两点:

  1. “窗口”对应的是一段可以被发送者发送的字节序列,其连续的范围称之为“窗口”;
  2. “滑动”则是指这段“允许发送的范围”是可以随着发送的过程而变化的,方式就是按顺序“滑动”

粘包问题的解决策略:

由于底层的TCP无法理解上层的业务逻辑,所以在底层是无法确保数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,归纳如下:

  • 消息定长,例如每个报文的大小为固定长度200字节,如果不够,空位补空格
  • 在包尾增加回车换行符进行分割,例如FTP协议
  • 将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息体长度)的字段,通常设计思路是消息头的第一个字段用int来表示消息的总长度
  • 更复杂的应用层协议

TCP粘包问题

注意:只有TCP有粘包现象,UDP永远不会粘包,因为TCP是基于数据流的协议,而UDP是基于数据报的协议

发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因。而UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据,这一点和TCP是很不同的。怎样定义消息呢?可以认为对方一次性write/send的数据为一个消息,需要明白的是当对方send一条信息的时候,无论底层怎样分段分片,TCP协议层会把构成整条消息的数据段排序完成后才呈现在内核缓冲区。

例如基于tcp的套接字客户端往服务端上传文件,发送时文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流从何处开始,在何处结束

所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

此外,发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据negal优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

negal优化算法:会将数据量小的,且时间间隔较短的数据一次性发给对方

  1. TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。
  2. UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。
  3. tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),那也不是空消息,udp协议会帮你封装上消息头,实验略

udp的recvfrom是阻塞的,一个recvfrom(x)必须对唯一一个sendinto(y),收完了x个字节的数据就算完成,若是y>x数据就丢失,这意味着udp根本不会粘包,但是会丢数据,不可靠

tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包。

两种情况下会发生粘包

  • 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包),也就是由于Nagle算法的原因导致。
  • 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) 。TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理。实际上,TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。

什么时候需要处理粘包现象

  1. 如果发送方发送的多组数据本来就是同一块数据的不同部分,比如说一个文件被分成多个部分发送,这时当然不需要处理粘包现象
  2. 如果多个分组毫不相干,甚至是并列关系,那么这个时候就一定要处理粘包现象了

拆包的发生情况

当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。

补充问题一:为何tcp是可靠传输,udp是不可靠传输

tcp在数据传输时,发送端先把数据发送到自己的缓存中,然后协议控制将缓存中的数据发往对端,对端返回一个ack=1,发送端则清理缓存中的数据,对端返回ack=0,则重新发送数据,所以tcp是可靠的

而udp发送数据,对端是不会返回确认信息的,因此不可靠

补充问题二:send(字节流)和recv(1024)及sendall

recv里指定的1024意思是从缓存里一次拿出1024个字节的数据

send的字节流是先放入己端缓存,然后由协议控制将缓存内容发往对端,如果待发送的字节流大小大于缓存剩余空间,那么数据丢失,用sendall就会循环调用send,数据不会丢失

TCP为什么是可靠地

TCP通过校验和、超时重传、确认应答和序列号、拥塞控制实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。

校验和:

发送的数据包的二进制相加然后取反,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。

确认应答+序列号(累计确认+seq):

接收方收到报文就会确认(累积确认:对所有按序接收的数据的确认)

TCP给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。

超时重传:

当TCP发出一个段后,它启动一个定时器等待目的端确认收到这个报文段如果不能及时收到一个确认,将重发这个报文段

流量控制:

TCP连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP使用的流量控制协议是可变大小的滑动窗口协议。

接收方有即时窗口(滑动窗口),随ACK报文发送

拥塞控制:

当网络拥塞时,减少数据的发送。

发送方有拥塞窗口,发送数据前比对接收方发过来的即使窗口,取小

慢启动、拥塞避免、快速发送、快速恢复

TCP的可靠传输是通过确认和超时重传的机制来实现的,而确认和超时重传的具体的实现是通过以字节为单位的滑动窗口机制来完成。

滑动窗口机制:

在TCP协议中窗口机制分为两种:固定的窗口大小、滑动窗口

固定窗口存在的问题:如果窗口过小,当传输比较大的数据的时候需要不停的对数据进行确认,这个时候就会造成很大的延迟。如果窗口过大,我们假设发送方一次发送100个数据,但接收方只能处理50个数据,这样每次都只对这50个数据进行确认。发送方下一次还是发送100个数据,但接受方还是只能处理50个数据。这样就避免了不必要的数据来拥塞我们的链路。

滑动窗口通俗来讲就是一种流量控制技术。

它本质上是描述接收方的TCP数据报缓冲区大小的数据,发送方根据这个数据来计算自己最多能发送多长的数据,如果发送方收到接收方的窗口大小为0的TCP数据报,那么发送方将停止发送数据,等到接收方发送窗口大小不为0的数据报的到来

滑动窗口实现了TCP流控制。首先明确滑动窗口的范畴:TCP是双工的协议,会话的双方都可以同时接收和发送数据。TCP会话的双方都各自维护一个发送窗口和一个接收窗口。各自的接收窗口大小取决于应用、系统、硬件的限制(TCP传输速率不能大于应用的数据处理速率)。各自的发送窗口则要求取决于对端通告的接收窗口,要求相同。

滑动窗口解决的是流量控制的的问题,就是如果接收端和发送端对数据包的处理速度不同,如何让双方达成一致。接收端的缓存传输数据给应用层,但这个过程不一定是即时的,如果发送速度太快,会出现接收端数据overflow,流量控制解决的是这个问题。

滑动窗口原理:

在图中,我们可看出灰色1号2号3号包已经发送完毕,并且已经收到Ack。这些包就已经是过去式。4、5、6、7号包是黄色的,表示已经发送了。但是并没有收到对方的Ack,所以也不知道接收方有没有收到。8、9、10号包是绿色的。是我们还没有发送的。这些绿色也就是我们接下来马上要发送的包。 可以看出我们的窗口正好是11格。后面的11-16还没有被读进内存。要等4号-10号包有接下来的动作后,我们的包才会继续往下发送。

可以看到4号包对方已经被接收到,所以被涂成了灰色。“窗口”就往右移一格,这里只要保证“窗口”是7格的。 我们就把11号包读进了我们的缓存。进入了“待发送”的状态。8、9号包已经变成了黄色,表示已经发送出去了。接下来的操作就是一样的了,确认包后,窗口往后移继续将未发送的包读进缓存,把“待发送“状态的包变为”已发送“。

丢包情况

有可能我们包发过去,对方的Ack丢了。也有可能我们的包并没有发送过去。从发送方角度看就是我们没有收到Ack。

发生的情况:一直在等Ack。如果一直等不到的话,我们也会把读进缓存的待发送的包也一起发过去。但是,这个时候我们的窗口已经发满了。所以并不能把12号包读进来,而是始终在等待5号包的Ack。

这时候我们有个解决方法:超时重传 这里有一点要说明:这个Ack是要按顺序的。必须要等到5的Ack收到,才会把6-11的Ack发送过去。这样就保证了滑动窗口的一个顺序。

TCP拥塞控制

提高网络利用率,降低丢包率,并保证网络资源对每条数据流的公平性,这就是拥塞控制。

拥塞控制包括四部分:慢启动拥塞避免快速重传快速恢复

发送端向网络一次连续写入的数据量,我们称为SWND(Send Window,发送窗口).但是发送端最终以TCP报文段来发送数据,所以SWND的大小限制了能连续发送的TCP报文段数量。这些TCP报文段的最大长度(仅数据部分)称为SMSS(Sender Maximum Segment Size,发送者最大段大小),其值一般等于MSS。

发送端需要合理的选择SWND的大小,如果SWND太小,会引起明显的网络延迟;反之,如果SWND太大,则容易导致网络拥塞。所以还需要引入一个称为拥塞窗口(Congestion Window,CWND)的状态变量

(1)慢启动

发送方维持一个拥塞窗口CWND的状态变量。它的大小取决于网络的拥塞程度,并且在动态的变化,发送方会让自己的发送窗口等于这个拥塞窗口。

发送方控制拥塞窗口的原则是:

(1)只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。

(2)但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。

慢启动算法:因为不清楚网络状况,所以需要进行试探,将发送窗口逐渐增大,也就是逐渐增大拥塞窗口的数值。在刚开始发送的时候,先把拥塞窗口CWND设置为最大报文段MSS,每收到一个对新报文段的确认后,就把拥塞窗口最多增加一个MSS数值。这种逐步增大的方法可以使分组注入到网络的速率更加合理。【指数增长】

为了防止拥塞窗口过大引起网络拥塞,我们需要设置一个慢开始门限ssthreth状态变量,当cwnd < ssthreth时,使用慢开始算法;当cwnd > ssthrerth时,使用拥塞控制算法;如果两者相等,两个都可以使用。

慢启动的“慢”并不是指CWND增长速率慢而是说在TCP开始发送报文时,先设置CWND=1,使发送端开始时只发送一个报文段进行探测。

(2)拥塞避免

就是让拥塞窗口缓慢增大,即每经过一个往返时间RTT就使cwnd+1,这种线性增长的速率慢很多。

只要发送方判断出网络拥塞,不论是在慢开始还是拥塞控制阶段,都要把慢开始门限值设置为出现拥塞时发送端窗口大小的一半,但不能小于2。然后把cwnd重新置为1,执行慢开始算法。

门限值减半,cwnd重置为1,做目的是减少发送到网络中的分组数,使得发生拥塞的路由器能够有时间能把队列中积压的分组处理掉。

发送端判断网络拥塞的依据:

①传送超时,即TCP重传定时器溢出

②收到重复的确认报文

(3)快重传

快重传算法要求接收方每收到一个失序的报文段后就立即发出重复确认,而不要等到自己发送数据时才进行捎带确认。发送方只要一连收到3个同样的确认报文就应当立即重传数据报,不必等待报文段的重传计时器到期。

发送端连续收到三个重复的ack时,表示该数据段已经丢失,需要重发

由于TCP包是封装在IP包内,IP包在传输时乱序,意味着TCP包到达接收端也是乱序的,乱序的话也会造成接收端发送冗余ACK。那发送冗余ACK是由于乱序造成的还是包丢失造成的,这里便需要好好权衡一番

(4)快恢复

i.当发送方连续收到三个重复确认时,执行“乘法减小”算法,慢启动门限减半,为了预防网络发生阻塞

ii.由于发送方现在认为网络很可能没有发生阻塞,因此现在不执行慢启动算法,而是把cwnd值设置为慢启动门限减半后的值,然后开始执行拥塞避免算法,拥塞窗口cwnd值线性增大。

TCP流量控制

如果发送端发送数据太快,接收端来不及接收,可能会丢失数据。所以流量控制是让发送端不要发送太快,要让接收端来得及接收

流量控制是通过大小可变的滑动窗口实现的。

发送端窗口大小不能超过接收端窗口大小的值。TCP窗口单位是字节。

为什么要设置窗口,因为如果TCP发完一次数据等待接收端确认再发下一条数据太慢了。

由图中可知,TCP三次流量控制分别是,第一次窗口大小由400减到300,第二次减到100,第三次减到0。

TCP连接的一方如果收到零窗口通知,就会启动坚持计时器。若坚持计时器的时间到期,就会发送一个零窗口控测报文段,收到报文段的一方就重新设置坚持计时器。

TCP长连接和短连接的区别

什么是长连接和短连接?

  • 长连接

    也叫持久连接,在TCP层握手成功后,不立即断开连接,并在此连接的基础上进行多次消息(包括心跳)交互,直至连接的任意一方(客户端OR服务端)主动断开连接,此过程称为一次完整的长连接。HTTP 1.1相对于1.0最重要的新特性就是引入了长连接

  • 短连接

    短连接,顾名思义,与长连接的区别就是,客户端收到服务端的响应后,立刻发送FIN消息,主动释放连接。也有服务端主动断连的情况,凡是在一次消息交互(发请求-收响应)之后立刻断开连接的情况都称为短连接。

什么时候用长连接,短连接? 长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。

而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。

全连接队列、半连接队列

当服务端调用listen函数监听端口的时候,内核会为每个监听的socket创建两个队列:

  • 半连接队列(syn queue):客户端发送SYN包,服务端收到后回复SYN+ACK后,服务端进入SYN_RCVD状态,这个时候的socket会放到半连接队列。
  • 全连接队列(accept queue) :当服务端收到客户端的ACK后,socket会从半连接队列移出到全连接队列。当调用accpet函数的时候,会从全连接队列的头部返回可用socket给用户进程。

半连接队列

半连接队列的大小由/proc/sys/net/ipv4/tcp_max_syn_backlog控制,Linux的默认是1024。

当服务端发送SYN_ACK后将会开启一个定时器,如果超时没有收到客户端的ACK,将会重发SYN_ACK包。重传的次数由/proc/sys/net/ipv4/tcp_synack_retries控制,默认是5次。

全连接队列

全连接队列的大小通过/proc/sys/net/core/somaxconn指定,在使用listen函数时,内核会根据传入的backlog参数与系统参数somaxconn,取二者的较小值。

流程简述如下

  1. 客户端发送SYN付服务端进行第一次报文握手, **此时服务端将此请求信息放在半连接队列中 **并回复SYN+ACK给客户端。

此处就是SYN Flood(后续关注,此篇记录)攻击的点,攻击方要做的就是不停的建立连接,但是确不给出ACK确认,导致半连接队列满了,其他请求无法进入。

  1. 客户端收到SYN+ACK,随机发出ACK确认给服务端;

**全队列未满 **:从半连接队列拿出此消息放入全队列中。

**全队列已满 **:处理方式和tcp_abort_on_overflow(cat /proc/sys/net/ipv4/tcp_abort_on_overflow)有关:

tcp_abort_on_overflow=0;表示丢弃该ACK;

tcp_abort_on_overflow=1;表示发送一个RST给客户端,直接废弃掉这个握手过程。

  1. 服务端accept处理此请求,从全队列中将此请求信息拿出。

listen函数

int listen(int sockfd, int backlog)

Nginx和Redis默认的backlog值等于511,Linux默认的backlog 为 128,Java默认的backlog等于50

默认情况下,全连接队列满以后,服务端会忽略客户端的 ACK,随后会重传SYN+ACK,也可以修改这种行为,这个值由/proc/sys/net/ipv4/tcp_abort_on_overflow决定。

  • tcp_abort_on_overflow为0表示三次握手最后一步全连接队列满以后服务端会丢掉客户端发过来的ACK,服务端随后会进行重传SYN+ACK
  • tcp_abort_on_overflow为1表示全连接队列满以后服务端发送RST给客户端,直接释放资源。

TCP与HTTP的关系,如何基于TCP实现HTTP

TCP是传输层协议,HTTP是应用层协议,HTTP是建立在TCP协议之上的一种应用。简单地说,TCP就是单纯建立连接,不涉及任何我们需要请求的实际数据,简单的传输。HTTP是用来收发数据的,即实际应用的。

第一:从传输层,我们和服务器端建立TCP连接,首先需要通过三次握手建立连接,简单地说就是:请求,确认,连接

第二:从实际上的数据应用来说http,在前面客户端与服务器建立TCP连接之后,就需要用HTTP来传送数据了。

TCP是底层通讯协议,定义的是数据传输和连接方式的规范

HTTP是应用层协议,定义的是传输数据的内容的规范

HTTP协议中的数据是利用TCP协议传输的,所以支持HTTP也就一定支持TCP

HTTP支持的是www服务

而TCP/IP是协议

它是Internet国际互联网络的基础。TCP/IP是网络中使用的基本的通信协议。

TCP/IP实际上是一组协议,它包括上百个各种功能的协议,如:远程登录、文件传输和电子邮件等,而TCP协议和IP协议是保证数据完整

传输的两个基本的重要协议。通常说TCP/IP是Internet协议族,而不单单是TCP和IP。

TCP与UDP的伪首部

pseudo header的作用: protection against misrouted segments,翻译一下就是避免协议栈接收到不“真正“属于自己的错误数据报

首先我们得了解一下pseudo header在协议栈中是如何使用的,在发送每一个TCP/UDP数据报的时候会填充pseudo header结构体,然后再和TCP头一起参与到检验码的计算中,在接收端会对收到的数据报进行校验码的验证,具体的参考:伪头部

伪首部并非TCP&UDP数据报中实际的有效成分。伪首部是一个虚拟的数据结构,其中的信息是从数据报所在IP分组头的分组头中提取的,既不向下传送也不向上递交,而仅仅是为计算校验和。这样的校验和,既校验了TCP&UDP用户数据的源端口号和目的端口号以及TCP&UDP用户数据报的数据部分,又检验了IP数据报的源IP地址和目的地址。伪报头保证TCP&UDP数据单元到达正确的目的地址。因此,伪报头中包含IP地址并且作为计算校验和需要考虑的一部分。最终目的端根据伪报头和数据单元计算校验和以验证通信数据在传输过程中没有改变而且到达了正确的目的地址。

乍一看这个解释觉得挺好理解的,但是稍微费点脑细胞一想,好像这个解释不太对啊!按照协议栈的处理数据报流程肯定是要先经过IP层的处理过滤掉不属于自己的IP数据报后才接着往上层处理的,怎么到了上层(TCP、UDP)还需要校验数据报是否属于自己呢?

Internet中的数据报会在传输过程中经过多跳(hop)才会到达最终的目的地址,在中间的任何一跳都可能会存在软件/硬件的错误,导致本来应该到达X的数据报到达了Y(修改了数据报中的dst address和IP层的checksum),这样的数据报可以顺利的逃过IP层的校验到达上层TCP/UDP。这个时候pseudo header就发挥它的作用了,通过计算数据报的校验码就能发现这是一个错误的数据报,它并是“真正“的属于我。

我能说我这个人比较喜欢瞎想吗?我怎么觉得上面的这个解释好像还是有点不太好理解了,既然我能修改IP层的数据那么我同样可以修改TCP/UDP层的数据啊,这样我把TCP/UDP中的校验码checksum重新计算修改成“正确“的值,这样这个数据报不就可以逃过IP层、TCP层的校验了吗?

是的,这样修改过的数据报是完全“正确“的,目的协议栈会认为这个数据报是合法的。也就是说pseudo header只能防“君子“不能防“小人“,pseudo header主要是为了修正中间网络设备的错误路由,因为中间路由设备一般都只会操作IP层不会操作TCP/UDP层,所以也就不会错误的修改TCP/UDP的checksum了。