TCP/IP 协议精讲-精华总结版本
序言
本文旨在介绍一下TCP/IP涉及得所有基础知识,为大家从宏观上俯瞰TCP/IP提供一个基石,文档属于《TCP/IP图解(第五版)》的精简版本。
专业术语
缩写 | 全称 |
WAN | Wide area network广域网 |
LAN | Local area network局域网 |
TCP | Transmission controll protocol传输控制协议 |
UDP | User Datagram Protocol |
IP | Internet Protocol |
ISP | Internet Service Provider |
IX | Internet Exchange |
NOC | Network Operation Center |
MTU | Maxinum transmission Unit |
DNS | Domain Name System |
ARP | Address Resolution Protocol |
DHCP | Dynamic Host Configuration Protocol |
1 基础知识
提到通信网络,不得不想到TCP/IP七层架构,由下图:
1.1 网络出现得背景
-
网络设备的广泛使用,处在现在的科技时代,智能设备已经不在讲究单打独斗,而是倾向于“万物互联”的生态理念,身边的电脑、手表、笔记本、电视、汽车...都离不开网络;
-
网络模式的切换,计算机诞生之初,每一台机器都是一个独立的设备,之间不能互相通信,如下图计算机1-3之间没有任何关联,用户如果想切换计算机只能移动实现,想到新中国成立之初,我们在研发核弹、核潜艇...时需要经过大量的计算从而得到科学的结果,但是那个时候国内计算机屈指可数,科研人员想要计算数据时只能来回奔波;
独立模式:
暂时无法在飞书文档外展示此内容
互联模式:
这种模式下不同的计算机之间可以进行信息共享;
暂时无法在飞书文档外展示此内容
-
通信方式的转变,最初的计算机通信是基于有线方式,比如将相同业务的计算机通过有线连接在一起,从而实现信息共享,形成一个局域网,而在新型的网络通信中,不在有此局限,用户可以访问到任何计算机的信息,就像我们坐在家里就可以访问到国务院下发的最新资讯;
-
有了网络之后,万物互联将不在是口号,而是做到了真真正正的信息共享,全球”一家“,巴以冲突的最新战况我们动动手指就能看到;
计算机网络规模分为两种:
1.WAN(wide area network)广域网
广域网是由多个局域网组成,就像我们几个人可以组对和其他城市的队伍竞技;
2.LAN(local area network)局域网
顾名思义,局域网就是一个特定区域或者网域环境,可以由交换机、路由器、计算机组合,就像我们几个人在一个网吧玩红警;
1.2 协议必要性
协议为多设备之间提供了一种规范,要求所有的设备都必须按照固定的规范执行,这样高度一致性,不管是什么厂商、平台...都可以正常通信;
1.3 OSI七层架构及作用
应用层:主要有各应用主导开发,例如邮件协议、文件传输协议;
表示层:负责将应用信息转化为可以利用网络传输的格式,例如在双端之间传输声音、视频等信息;
会话层:通信管理协议,负责建立和断开通信连接;
传输层:负责端到端的数据传输,TCP/UDP是典型代表;
网络层:主要负责地址管理域路由选择,IP是典型代表;
数据链路层:双端直接传输的数据,负责将数据转换为比特流,802.11是典型代表;
物理层:负责将数字信号转化为电信号/光信号并进行传输;
1.4 网络的构成要素
一个完整的网络至少需要包含以下几个要素:
-
网卡:使计算机联网的设备;
-
中继器:从物理层上延长网络的设备,可以对信号进行放大和传输;
-
网桥/2层交换机:从数据链路层上延长的设备;
-
路由器/3层交换机:通过网络层转发分组数据的设备;
-
4~7层交换机:处理传输层以上各层网络传输的设备;
-
网关:转换协议的设备;
1.5 传输数据和吞吐量
传输速率:(bps)
在数据传输过程中,端到端之间数据流动的物理速率就是传输速率,传输速率高不是指单位时间流动的数据速率有多快,而是指单位时间数据的传输量有多少,举个例子,低速率就好比日常生活中车道少的公路,汽车通路的时间就比较久,而高速率就好比车道多的公路,汽车通过就比较快,那传输速率就好比这一段时间通过的车辆;
传输速率就可以说是带宽,带宽越大,传输速率越大;
那对wifi而言,影响数据传输数量的因子有哪些呢,如下表格,列出来所有的因子,我们在拆解一个吞吐问题时,首先就需要check这些硬性条件是否满足(带宽、空间流、调制解调方式、GI等等):
吞吐量:
端到端之间实际的传输速率被称为吞吐量,影响吞吐量的因素有这么几个:
(1)带宽;
(2)CPU处理能力;
(3)网络的拥堵程度;
(4)报文中数据字段的占比(不含报文头,只计算数据段本身);
.......这几个因素也将作为后续排查网络断流问题的外部因素;
2 TCP/IP基础知识
TCP/IP更广义的定义并不是单单指TCP/IP两种协议(当然就是这么说也没毛病),但是他们往往是指一个协议家族:
定义协议的组织被称为是RFC,如何从网络中获取协议文档参考链接如下:
RFC协议获取指导
2.1 新协议标准化流程
2.2 TCP/IP通信流程
2.2.1 数据"身份证"
根据OSI七层架构来看,每一个数据包从应用发送给接收端,都需要经过每一层协议栈层层包装,如下图:
每一层都会对所发送的数据进行封装处理,添加一个首部,这个首部通常包含该层必要的信息,比如发送的目标地址以及协议的相关信息,数据包 = 协议头 + 数据;(上一层的整个包都会被下一层视为其数据包)
这里我们可以抓一份数据报文来看:
2.2.2 发送数据包
我们举个例子,我们通过飞书给某位同事发送一个文件压缩包/语音/文字,看看各层都做了什么:
(1)应用程序处理
在文本框编辑好文字之后,从点击发送图标开始,应用程序开始建立TCP连接,当然,他首先会对要发送的内容进行编码;
(2)传输层
这里的传输层也可以理解为TCP协议,传输层负责建立、断开TCP连接以及发送数据;
TCP收到应用发来的数据后,会做以下事情:
-
为数据添加TCP包头,包头中将包含以下内容:
-
将封装好的数据发送给IP;
(3)网络层
这里可以理解为是IP协议,IP负责以下内容:
-
将收到的TCP包整体当作数据包并添加IP包头,这里将会包含源/目标MAC地址,如果不知道MAC地址,将会通过ARP协议进行寻址,包头内容如下:
-
将封装好的数据发送给驱动程序,也称为数据链路层,这里才开始正真的数据发送;
Mark:这里值得注意的是IP包头中的TTL字段,他表示这个字段在穿过多少个路由之后被抛弃,当IP没穿过一个路由器就会-1,当他变成0之后就会被自动抛弃;
(4)数据链路层
这里基本是驱动程序,像802.11、以太网、数据网协议都在这一层,拿802.11举例,驱动程序在拿到数据包之后,负责以下事情:
-
给网络层数据包加上802.11协议包头以及标志802.11的协议,截图如下:
-
将封装好的数据包交给物理层传输给数据端;
数据包从应用出来后,经过每一层,都会添加一个包头,802.11包头、IP包头、TCP包头以及应用自己的包头,在链路层还会添加一个包尾;每个包头中至少包含两个信息:
(1)发送端和接收端的地址,数据链路层是MAC地址,网络层是IP地址,传输层是端口号;
(2)上一层协议的类型;
Mark:传输层和数据链路层都有校验数据完整性的功能;
2.2.3 接收数据包
数据接收过程与发送过程相反,下边简单描述下各层协议的任务;
(1)数据链路层
-
从802.11数据包中找到MAC,判断是否是发给自己的,如果不是就直接丢弃;
-
查找包头中类型域,确认包类型交给上一层对应的协议处理;
(2)网络层
-
从IP包头里解析IP地址确认是否是发给自己的包,如果不是直接丢弃;
-
查找包头中类型域,确认包类型交给上一层对应的协议处理;
-
在有路由转发的情况下,接收端地址往往是路由设备的地址,此时需要根据路由控制表转发给对应的终端;
(3)传输层
-
计算校验和,确认数据是否被损坏;
-
检查接收数据序号、检查端口号,确定具体的应用;
-
传输给对应的应用,注意数据校验完之后会发送一个ACK确认,如果这个ack没有到达,就会重传;
3 数据链路
数据链路层是TCP/IP的基础,如果没有数据链路,TCP/IP也将无从说起,本文主要介绍数据链路的基础知识,具体协议以802.11为载体;
3.1 数据链路层的作用
数据链路层的几个作用在这里简单介绍下:
-
端到端之间传输数据时,说白了就是数字信号和光/电信号的转变,转变为光/电信号正是数据链路层和物理层的作用;
-
数据链路层是数据传输的最小单位;
-
数据链路层定义了各种通信媒介之间通信的规范;
3.2 数据链路相关的技术
3.2.1 MAC地址
MAC地址相当于数据链路层的ID,端到端之间通信依赖于MAC地址,因此世界上任何两台无线设备都不应该具备相同的MAC地址,MAC地址长度是48b,结构如下:
第1位:单播/多播地址(0/1)
第2位:全局/本地地址(0/1)
第3~24位:由IEEE组织分配,不能重复
第25~48位:由各个厂商直接管理,不能重复
无线设备驱动厂商的识别码称为厂商识别码,即Organizationally Unique Ideifier,简称OUI,OUI官网查询链接:OUI官网查询(在这个链接里我们可以看到任何一家厂商的OUI信息)
3.2.2 共享型网络访问控制方式
共享网络是指多设备共用一种传输介质,例如多个wifi设备之间共用一个信道进行收发数据,收发数据时都需要获得传输介质,这里就用到了CSMA/CD方式,CSMA/CD要求每个设备发送数据前都需要进行冲突检测以会的数据传输间隙,其工作原理简单描述就是:
-
检测载波信道上有没有数据波动/能量波动,如果没有则可以发送数据;
-
如果有波动,就需要立即释放载波信道,并随机退避一段时间,等待时间间隙归零后重新接入载波信道开始检测;
-
这是一种半双工通信模式;
其具体的工作原理参考这篇文章:DCF之CSMA/CD
3.2.3 非共享型网络访问控制方式
非共享型网络就是指传输介质不共享,端到端直接点对点的连接,例如家庭台式机通过网线与交换机相连,由交换机转发数据,它是一种全双工通信模式;
这里简单说一下半双工&全双工通信的差异
半双工:同一时间只能同时发送数据或者同时接收数据;
全双工:同一时间可以同时发送数据和接收数据;
3.2.4 MAC地址转发
在使用同轴网络的以太网等介质共享环境中,同一时间只能允许一个接入设备收发数据,因此每个设备收发数据时都需要通过竞争手段获取对介质的控制权限,如此,如果同一个环境中接入的设备数量很庞大时,很明显的一个弊端就是传输效率底下;
为了解决这一弊端,就引入了交换机设备,在以太网中,一台交换机有多个端口,他们可以根据以太网中每个设备MAC地址决定使用哪个端口转发,这时端口与MAC地址对应的关系表就成为路由表;这个表一般不需要人为手动配置,大部分机器有自学功能,如下:
Mark:在端口不知情的情况下,端口会给每个连接的设备都发送一个包,在收到其中一个设备回复时,就将此设备MAC地址以及端口号记录下来,这也是其自学习的过程;
3.2.5 环路检测技术
在使用了交换机的网络环境中,如果其中一条网络通路发生变换,怎么避免一个数据包被反复的发送到一条有问题的链路上导致数据包丢失呢?
环路检测技术就是用来检测这一问题,在设备直接建立好连接后,会定时的去探测可用的链路,这里提到两种技术:生成树和源路由,如下:
网络管理可以设置在规定时间内在各个环路之间进行探测,以确定哪些端口可以使用哪些端口不能使用,同时,网络管理员也可以设置每个端口之间的权重,规定优先使用哪条环路进行通信,并且在发生问题之后切换备用环路进行通信;
其实在Android Wi-Fi架构设计中,也大量的使用了这个思路,比如系统会设置Wi-Fi、数据等链路的权重,根据不同的场景哪些链路优先级最高,其次,在DNS、HTTPS探测中也使用备用的地址.....
源路由方法:它是指在传输数据帧时,有效记录设备的源MAC地址并保存到本地,在链路发生故障时,直接向源路由发送数据;
3.3 无线局域网
无线通信通常使用电磁波、红外线、激光等媒介进行传输,其传输不需要任何网线;架构图:
无线LAN连接示意图:
4 IP协议
IP即Internet Protocol,翻译为国际网络,属于网络层,负责将数据包发送给目标计算机,它可以把世界上任何两台计算机关联到一起;
4.1 IP概述
在网络七层架构里,IP/网络层可以理解成重要桥梁,其上连接传输层(TCP,以端口作为连接标识),其下连接数据链路层,IP传输数据包可以跨越不同的数据链路层,以IP地址作为连接标识;
4.2 IP基础
IP模块涉及的知识块大致围绕三块:IP寻址、路由以及IP的分包与组包;
4.2.1 IP地址
如前文描述中,不同的网络分层架构中,都有一个唯一的标识用来传输数据,传输层是采用的端口号,而数据链路层是采用了MAC地址作为唯一标识进行传输,那么,IP层也有自己的唯一标识 -- IP地址;
4.2.2 路由控制
在一个大型网络中,涉及到多个路由,而端到端的传输一般都需要经过这些路由多次转发才能到达目标终端,而这个转发的过程就是路由控制,每一个转发路由中都应该维护这一张路由表,他不指定终端与终端的地址,而是单独指定其下一级地址;
4.2.3 数据链路层的抽象化
IP协议的主要作用就是用来传输多个数据链路层的数据,因此对于这些链路层的特性抽象化也是IP层重要作用之一,对于IP层来说,无论底层数据链路层是什么协议,对于IP来说都是一视同仁,而数据链路层之间最大的区别就是最大传输单元不同(MTU);一个典型的场景就是手机使用数据上网,同时开启热点为其他设备提供数据网络,那么这个转发过程如下:
暂时无法在飞书文档外展示此内容
手机使用数据上网时,是通过基线交互获取上网数据,数据链路层是以太网,而STA上网时,是通过AP将数据转发给Data,从而获取基站的上网数据,这里数据链路层是802.11,AP充当了一个转发路由的角色;
4.2.4 IP属于无连接型
在此之前,我们肯定听说过TCP是属于连接型网络,而UDP属于无连接型,这里强调一下,IP也是面向无连接的,数据到达IP层之后,无需建立连接,他会直接进行转发;问几个问题,看看大家能回答上来嘛;
(1)IP为什么采用无连接型呢?
一二三,时间到~
这里应该有两个考虑,一个是简化管理,因为管理各种各样的链路本来就是一个耗费时间的操作,另外一个就是为了提速,因为如果每次传输都需要先进行连接,那么,处理效率就会很低,IP层不连接,而是交给上层协议TCP进行连接管控,这也是协议分层的一个重要目的;
(2)为什么不让IP层具备可靠传输的功能,将协议合并?
一二三,这里留给读者考虑一下,欢迎各位大佬评论区留言;
4.3 IP地址的基础知识
在TCP/IP进行传输时,每个终端都必须设置正确的IP地址,如果IP地址设置不符合规范或者IP地址冲突,通信就不能正常交互;
4.3.1 IP地址的定义
IP地址的表现形式:32位形式;
计算机如何处理IP地址:计算机处理IP地址都是以二进制形式表示,32位;
10101100. 00010100. 00000001. 00000001(二进制)
172 . 20 .1 . 1 (十进制)
在人的世界里,并不习惯二进制形式,因为我们看到的IP都是十进制的,如果按照二进制进行推算的话,那么IP地址池里有多少地址可以分配给计算机:
2^32 = 4 294 967 296;
根据这个数值进行推算,可以为43亿个网口分配IP地址,这里有一个理解误区就是一个计算机并不是只能拥有一个IP地址,例如我们一个手机设备,STA会有一个IP地址,SAP会有一个IP地址,数据会有一个IP地址,P2P会有一个IP地址;
4.3.2 IP地址的组成
IP地址 = 网络标识 + 主机标识
例如:192.168.31.11/24
网络标识必须保证在同一连接的数据链路上有不同的指,或者在相同的网段下,必须保证有不同的主机标识,总之,每台主机或者网口不能有相同的指,要么网络地址不同,要么主机标识不同;一图说明如下:
//主机标识相同时,网络标识必须不同
4.3.3 IP地址的分类
IP地址可以划分为四类:A、B、C、D类;
本节我们脑海里要有一个标准的二进制地址的格式:00000000.00000000.00000000.00000000;
A类:首位以0表示,1-8用来作为网络标识,9-32用来作为主机标识,其范围是0.0.0.0 ~ 127.0.0.0,计算方式如下图:
最小==》00000000.00000000.00000000.00000000转化为十进制是0.0.0.0;
最大==》01000000.00000000.00000000.00000000转化为十进制是127.0.0.0;
B类:前两位以10表示,1-16是网络标识,17-32是主机标识,其范围是128.0.0.1 ~ 191.255.0.0;
C类:前三位以110表示,1-24是网络标识,25-32是主机标识,其范围是192.168.0.0 ~ 239.255.255.0;
D类:前四位是1110表示,1-32是网络标识,没有主机标识,常用来作为多播地址,其范围是224.0.0.0 ~ 239.255.255.255,经常用来作为多播地址使用;
因此,A、B、C、D类地址的范围用二进制表示分别如下(表示最大):
01111111.00000000.00000000.00000000
10111111.11111111.00000000.00000000
11011111.11111111.11111111.00000000
11101111.11111111.11111111.11111111
(以上1是网络标识部分,0是主机标识部分)
Mark:
(1)如果要用比特位表示主机地址时,不可以全部为0或者1;
(2)全部为1的主机地址默认为广播地址,全部为0的主机地址经常是未获取IP的默认地址;例如如果主机地址中出现了十进制的255,那么这个地址大概率就是一个广播地址;
4.3.4 子网掩码
4.3.4.1 子网掩码解决了IP地址分类带来的浪费
根据之前章节的描述可以知道,一个IP地址只要确定了分类,我们就知道其中网络标识和主机标识,例如我们根据网络标识的分类可以确定每个类别:
A类 11111111.00000000.000000000.00000000 -- 255.0.0.0
B类 11111111.11111111.000000000.00000000 -- 255.255.0.0
C类 11111111.11111111.111111111.00000000 -- 255.255.255.0
网络标识相同的计算机必须属于同一个链路,例如一个B类地址的网络架构中,理论上一个链路上允许6.5W多台计算机,然而实际网络环境中一半不会有这么多设备同时连接,因此如果我们直接使用A/B类IP地址的话,就显得很浪费;
4.3.4.2 子网与子网掩码
现在,一个 IP 地址的网络标识和主机标识已不再受限于该地址的类别,而是由一个叫做"子网掩码"的识别码通过子网网络地址细分出比 类、 类、更小粒度的网络。这种方式实际上就是将原来 类、 类等分类中的主机地址部分用作子网地址,可以将原网络分为多个物理网络的一种机制。自从引入了子网以后,一个 IP 地址就有了两种识别码。一是 IP 地址本身,另一个是表示网络部的子网掩码。子网掩码用二进制方式表示的话,也是一个 32位的数字。它对应 IP 地址网络标识部分的位全部为 "1" ,对应 IP 地址主机标识的部分则全部为 "0" 。由此,一个 IP 地址可以不再受限于自己的类别,而是可以用这样的子网掩码自由地定位自己的网络标识长度。当然,子网掩码必须是 IP址的首位开始连续的 "1" "。对于子网掩码,目前有两种表示方式。以 172.20.100.52 的前 26 位是网络地址的情况为例,以下是其中一种表示方法,它将 IP 地址与子网掩码的地址分别用两行来表示。
形式一:
IP 地址 172.20.100.52
子网掩码 255.255.255.192
网络地址 172.20.100.0
子网掩码 255.255.255.192
广播地址 172.20.100.63
子网掩码 255.255.255.192
形式二:通过一个/加后缀,标识网络标识的位数,例如/24就表示IP地址的前24位是网络标识
IP地址:192.168.31.1/24
网络地址:192.168.31.0/24(0可以省略)
广播地址:192.168.31.63/24
4.4 IP数据包分片&聚合
4.4.1 MTU类别
MTU就是MAX Transmission Unit最大传输单元,表示数据包数据长度的基本单位,例如4.2.3章节描述,不同的物理层其MTU不尽相同:
4.4.2 IP数据包的分片与聚合
由于不同物理层的限制,分片和聚合是必要的,例如,在一个以太网络环境中,支持的最大MTU是1500字节(包含了首部协议标识),如果发送端要发送4323字节的数据包,就需要先在发送端进行分包,接收端收到之后在进行重组;
如何分包?
(1)路由收到转发数据之后计算数据长度;
(2)如果带转发数据长度大于MTU,则进行分包;
(3)设置一个唯一标识;
(4)接收端根据标识符进行聚合;
我们实际看一下路由的分包与聚合:
暂时无法在飞书文档外展示此内容
分包:
聚合:
4.4.3 路径MTU发现
基于上边介绍的分片机制,我们思考几个问题:
(1)分片机制解决了设备之间大数据包的发送,如果大量的大数据包持续发送,并且路由需要转发多个设备的大数据包,负载如何?
(2)大数据包被分片之后,如果因为环境因素导致某个包丢失,这个传输后果如何?
欢迎各位大神评论区解答。
那么有没有一种方式可以解决分片之后导致的一系列问题,当然有了,这就是路径MTU发现功能;
通俗来说,路径MTU发现就是探测接收端支持的最大MTU,之后按照MTU之内的数据长度进行发包,如下图:
(1)首先发送端发送的IP报文里标识分片为false;
(2)路由收到之后由于数据报文长度太长,丢失;
(3)路由发送一个不可达的icmp通知发送端其支持的最大MTU;
(4)发送端发送符合MTU的数据包;
(5)如此反复,直到接收端收不到icmp为止;
4.5 IPV6
4.5.1 为什么需要ipv6
(1)ipv6可以解决ipv4地址被耗尽的缺陷,ipv4的地址长度是4个8位字节,即32比特,而ipv6的地址长度是128比特,一般可以写成8个16位字节;
(2)ipv6可以弥补ipv4的缺陷,目前大部分的无线产品开始兼容ipv6;
4.5.2 IPV6有什么好处
(1)IP地址扩大,防止路由表膨胀;
(2)性能提升,IPV6仅支持MTU路径发现,将减小分片带来的性能,包首部长度固定,简化了包首部结构,减小路由的负荷;
(3)支持即插即用,即使没有DHCP服务器也可以实现分配IP;
(4)更加安全,采用了认证和加密功能;
4.5.3 IPV6中IP标记方法
对于IP地址,我相信大部分小伙伴看到这俩个格式的地址会产生不同的感觉:
IPV4:192.168.31.1 -->这是一个IP地址
IPV6:fe80:a415:9ff:fe3a:18c0/64 -->这是什么?
IPV6的地址长度是128位,他能表示38位数(2^128 ~ 3.4 * 10^38),也就是说也可以为这么多用户分配IP(小编不知道这是多少),如果按照ipv4用十进制表示的话,就是16个数字,这样就很长,因此习惯上我们以16进制来表示一组,每组中间用:隔开,如果连续的两段为0时,可以忽略,但是一个IPV6地址最多只能出现一次::;
IPV6地址标记举例:
二进制
1111111011011100:1011101010011000:0111011001010100:
0011001000010000:1111111011011100:1011101010011000:
0111011001010100:0011001000010000
十六进制
FEDC:BA98:7654:3210:FEDC:BA98:7654:3210
IPv6 IP 地址省略举例
二进制
0001000010000000:0000000000000000:0000000000000000:
0000000000000000:0000000000000000:0000100000000000:
0010000000001100:0100000101111010
十进制
1080:0:0:0:8:800:200C:417A
1080::8:800:200C:417A (省略后)
4.5.4 IPV6分片处理
IPV6分片不需要路由参数,而是直接在发送端进行,因此”MTU路由发现“功能必不可少,IPV6中最小MTU是1280字节,如果对于系统资源比较紧张的设备不需要进行MTU路由发现,可以直接按照1280字节发送数据包;
4.6 ipv4首部
这一节我们解析下IPV4首部结构:
版本:
占位4比特,如果是IPV4那么这个值就是4,不同协议版本:
如果遇到我们不知道的协议版本号,可以查阅这个网址:
http://www.iana.org/assignments/version-numbers
首部长度:
4比特,表示IP首部的大小,对于没有可选项的IP包,首部长度设置为“5”,也就是说IP的首部长度为20字节(4*5);
区分服务(TOS: Type Of Service):
8比特,用来表示服务质量,每一位含义如下:
这部分主要与应用强相关,系统层面的网络基本会无视这一段报文;
这里重点解释下ECN报文,Explicit Congestion Notification显式拥塞通告,主要用来报告网络拥堵的情况,有两个比特组成:
ECT表示TCP是否处理ECN,如果处理表示为1,CE表示网络是否拥塞,如果拥塞,表示为1;
总长度:
16比特,因此IP包最大数据长度是2^16 ~ 65535;
标识:
16比特,用于分片,同一个分片这个值相同,通常没发送一个IP包,这个值+1,此外,即使ID相同,但是源/目标MAC地址不同的话,也会认为是不同的分片;
标志:
3比特,这里是分片相关的信息,具体的含义如下:
片位移:
13比特,用来标识被分片的每一个数据包相对于初始数据包的位置,第一个分片对应的值为 。由于 FO 域占 13 位,因此最多可以表示 8192 (= 13 个相对位置。单位为 字节,因此最大可表示原始数据加8192=65536 字节的位置。
TTL:
8比特,标识一个数据包可以经过多少路由转发,每经过一次转发,值-1;
协议:
8比特,标识IP包头属于哪一个协议,具体的协议如下表格:
首部校验和(Header Checksum):
16比特,也叫IP首部校验和。该字段只校验数据报的首部,不校验数据部分。它主要用来确保 IP 数据报不被破坏。校验和的计算过程,首先要将该校验和的所有位置设置为 ,然后以 16 比特为单位划分首部,并用补数'计算所有 16 位字的和。最后将所得到这个和的 补数赋给首部校验和字段。
源地址&目标地址:
均是32比特,标识发送/接收的IP地址;
可选项:
长度不固定,一般在实验时使用,可以忽略;
数据(Data):
存入数据,将IP协议上层的首部作为数据段存入;
4.7 ipv6首部
这里大部分和IPV4类似,并且删除了某些IPV4报文字段用来提升IPV6的性能,小编这里不做进一步拆解,小伙伴有问题欢迎留言讨论;
5 IP协议相关技术
IP,网络协议,其目的是将数据包传递到目标主机,思考一个问题,想要完成这个过程,需要哪些必不可少的步骤呢?(1、2、3时间到)
(1)需要完成目标主机IP&MAC地址的解析;
(2)数据包传输过程中异常处理的功能;
5.1 IP协议是否可以完成以上所有工作?
很显然不可以,根据前四篇文章的介绍,我们知道,应用发送一个数据包,需要经过传输层、网络层、数据链路层以及物理层层层封装,而不同的层次都负责了不同的任务,例如传输层的是按照端口传输,网络层是按照IP地址传输、数据链路层是通过MAC地址传输,物理层主要负责数字信号和电信号/光信号的转化,因此仅仅依靠IP协议是根本无法完成传输的,我们举一个非常通俗易懂的例子,我们在终端发起一个ping www.baidu.com的命令,是如何得到服务器回复的(1、2、3时间到)~ (1)会话层:首先,服务器并不能识别字符串代表什么,因此需要通过DNS解析一个IP地址,发送端发送一个HTTP会话到这个IP地址;
(2)传输层:添加传输层首部,系统为这个数据包分配一个端口号,发送端使用该端口号向接收端发起请求,建立socket连接,然后发送给网络层;
(3)网络层:添加网络层首部,网络层收到这个数据包之后,查找路由表将数据包转发给接收端,这里可能需要很多次转发,当然这个路由表是在路由侧维护的,然后发送给数据链路层;
(4)数据链路层:添加数据链路层首部,通过邻居协议ARP(arp request/reply)/ipv6邻居协议(NS/NA)查找接收/发送端对应的MAC地址;
(5)物理层:通过传输媒介将数据包发送到空口当中,直到到达接收端;
涉及到的协议:
(1)应用层
http - www访问协议;
(2)传输层
TCP - 为HTTP提供可靠的数据传输;
UDP - 传输音频、视频流,包括DNS也是基于UDP实现;
(3)网络层
Icmp - 链路传输质量控制,延时、MTU路由发现、差错检查、链路可达等;
DNS - 实现域名&IP之间的转换、网络校验;
ARP - 实现IP地址&MAC地址之间的转化;
......
可以看到一个数据包的传输是需要经过多种协议协同配合的,因此本章我们简单整理下各个协议细节;
5.2 DNS
DNS request:
DNS response:
DNS的主要作用就是实现将由罗马字和点组成的字符串转化为计算可以识别的IP地址;DNS协议同时适用于IPV4&IPV6;
5.2.1 为什么需要DNS协议
试想一下,如果没有DNS协议,我们想要访问一个服务器或者主机时,都需要输入对应的IP地址,在现代网络中,一个网络拓扑结构中存在大量的机器,如果我们想要实现互相的通信,就必须人手一本IP”新华字典“,显然这样是不现实的,这个时候我们如果只需要输入主机名/域名,就比较方便了;
5.2.2 DNS域名系统的作用
在端到端的通信过程中,目前无非两种方式,通过IP地址或者主机名,IP地址不方便记忆,通过我们会使用主机名进行通信,DNS服务器可以将这个主机域名转换为IP地址;
Linux系统上通常可以使用nsloopup查询IP地址
-MT:~$ nslookup www.baidu.com
Server: 127.0.0.53
Address: 127.0.0.53#53
Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com.
Name: www.a.shifen.com
Address: 220.181.38.150
Name: www.a.shifen.com
Address: 220.181.38.149
Name: www.a.shifen.com
Address: 240e:83:205:58:0:ff:b09f:36bf
Name: www.a.shifen.com
Address: 240e:83:205:5a:0:ff:b05f:346b
5.2.3 Internet DNS域名的树形结构
上图展示了 DNS 服务器的部分层次结构,从上到下依次为根域名服务器、顶级域名服务器和权威域名服务器。域名和IP地址的映射关系必须保存在域名服务器中,供所有其他应用查询。显然不能将所有信息都储存在一台域名服务器中。DNS使用分布在各地的域名服务器来实现域名到IP地址的转换。
域名服务器可以划分为以下四种不同的类型:
-
根域名服务器
:根域名服务器是最高层次的域名服务器。每个根域名服务器都知道所有的顶级域名服务器的域名及其IP地址。因特网上共有13个不同IP地址的根域名服务器。当本地域名服务器向根域名服务器发出查询请求时,路由器就把查询请求报文转发到离这个DNS客户最近的一个根域名服务器。这就加快了DNS的查询过程,同时也更合理地利用了因特网的资源。 -
顶级域名服务器
:这些域名服务器负责管理在该顶级域名服务器注册的所有二级域名。当收到DNS查询请求时就给出相应的回答(可能是最后的结果,也可能是下一级权限域名服务器的IP地址)。 -
权限域名服务器
:这些域名服务器负责管理某个区的域名。每一个主机的域名都必须在某个权限域名服务器处注册登记。因此权限域名服务器知道其管辖的域名与IP地址的映射关系。另外,权限域名服务器还知道其下级域名服务器的地址。 -
本地域名服务器
:本地域名服务器不属于上述的域名服务器的等级结构。当一个主机发出DNS请求报文时,这个报文就首先被送往该主机的本地域名服务器。本地域名服务器起着代理的作用,会将该报文转发到上述的域名服务器的等级结构中。本地域名服务器离用户较近,一般不超过几个路由器的距离,也有可能就在同一个局域网中。本地域名服务器的IP地址需要直接配置在需要域名解析的主机中。
5.2.3 DNS域名解析过程
DNS域名解析有两种方法:递归查询 & 迭代查询;
递归查询:
递归查询就是,如果本地主机想要访问一个服务器资源,本地域名服务器并不知道这个服务器域名对应的IP,那么本地域名服务器将携带这个请求向上一级域名服务器查询,直到查询到目标IP为止,用一张图来说明就是:
迭代查询:
相比递归查询,迭代查询不同的地方在于,每一级DNS域名服务器并不会抓发dns请求,当一个DNS请求到达一个DNS服务器后,如果这一级DNS服务器找不到目标IP地址,将会返回给上一级一个推荐的DNS域名服务器,接下来主机则会向这个推荐的DNS服务器发起请求,直到查询到这个目标IP地址,用一张图来说明就是:
5.2.4 DNS主要记录
IP以及域名的对应关系只是DNS系统的一部分,DNS域名系统管理的信息还包含如下部分:
5.3 ARP
ARP,又称Address Resolution Protocol地址解析协议,用来获取设备IP对应的MAC地址,ARP只适用于ipv4,IPv6对应的寻址协议是ICMPv6;
5.3.1 ARP报文格式
ARP包含两种包类型:arp request、arp response;
//arp request
//arp response
5.3.2 ARP是如何获取到对端MAC的
这里使用一张图来说明:
值得注意的是arp request是广播包,arp reply是单播包;
5.3.3 ARP缓存
通过上文我们知道,ARP协议是为了发送数据包之前获取到接收端的MAC地址,那么,如果每次发送一个数据包就需要发送一次arp,这显然增大了网络流量,传输效率也会很低,因此,我们通常会把获取到的IP地址 - MAC地址映射关系保存到缓存表里一段时间,下次发送数据包的时候就需要重新发起请求,不过,这个缓存表只能保存一段时间,超过这个期限将会重新请求;
发送端发送arp时,如果接收端没有回复时将会重新尝试,重新尝试的次数一般写在设备这个节点
cat /proc/sys/net/ipv4/neigh/wlan0/ucast_solicit(广播)
cat /proc/sys/net/ipv4/neigh/wlan0/mcast_solicit(组播)
5.3.4 ARP协议的必要性
ARP作为IP - 数据链路层的纽带,用来实现IP - MAC的查找,我们解读其必要性通过解释这么一个问题来说明;
问题 - 如果我们发的数据包没有IP或者MAC,数据包是否可以到达目标主机?
我们用这个图来解答这个问题;
首先,如果PC1向PC2发送数据包不需要IP地址,当设备PC1向PC2发包时,在路由学习MAC地址之间,并不知道这个数据包应该发给谁,这个时候路由可以选择向全世界所有的设备发包,在学习到所有MAC地址之后维护到路由表里,这样将造成极大的流量浪费&系统资源;
其次,如果PC1向PC2发送数据包不需要MAC地址,PC1向PC2发送数据包时,只有IP地址,当这个数据包到达Route1之后,其并不知道下一路由是谁(下一路由就是MAC地址中的DA mac),或许也可以向所有设备发包,但是这样就同样会导致流量浪费;
所以IP&MAC缺一不可;
我们按照上图实际抓空口包来看一下这个过程:
5.4 ICMP
5.4.1 ICMP扮演的角色
基于此前的文章分析,我们知道ICMP可以用来进行MTU路由发现,这一章就集中整理下ICMP都用来做什么;
(1)MTU路由发现,具体功能我们在4.4.3已经分析了,忘记的同学可以回去再看看;
(2)确认IP数据包是否正确发送,如果未正常达到,发送ICMP包通知具体原因;
(3)网络质量探测,通过ping延迟判断网络是否是通的以及干扰程度;
(4)设备软件是否存在问题,例如通过ping入测试设备软件RX性能的健壮性,关于这个话题-如何定位ping入问题本后的软件原因,小编想了想后边还是单独拉一个专题出来整理(Wi-Fi兼容性);
(5)工具刀,如果我们把一个网络结构想象成一个庞大的电路设计,如果其中某处供电有问题,我们都可以使用ICMP包进行检查,小编做这个比喻的目的就是为了提醒大家,ICMP包的作用并不是一两句话可以陈列完毕,在日常开发过程中,它可以做到方方面面,开发者脑洞有多大,他的作用就有大多,所以我们拿到一份网络报文,如果看到ICMP包,请先尝试解读一下他的上下文,在为的功能定性;
这里例举一种IP包没有正常送达目标机器的错误通知机制:
5.4.2 ICMP消息类型
-
ICMP目标不可达消息(类型3)
当路由器无法将IP数据包发送给目标地址时,会给发送端返回这个消息,我们实际当中遇到最多的就是代码1(Host Unreachable),它是指路由表里没有目标主机,或者目标主机没有接入网络;消息4(Fragmentation Needed and Don't Fragment was Set)就是4.4.3节提到的路径MTU发现;
还有一些其他的消息类型如下,这里不一一描述,小伙伴可以在实际开发当中遇到时在临时抱佛脚:
5.5 DHCP
DHCP,即Dynamic Host Configuration Protocol动态地址分配协议,可以实现为每一台主机分配IP地址的协议,它同时适用于IPV4、IPV6;
5.5.1 DHCP优势 - 即插即用
DHCP server可以主动为每一台主机分配IP地址:
5.5.2 DHCP工作机制
客户端设备如何从DHCP服务器上获得IP地址,一般来说DHCP分配IP地址有两种方式:
(1)DHCP server选出一个特定的IP分配给IP;
(2)为某个MAC地址分配固定的MAC;
//DHCP整体流程
5.6 NAT
5.7 IP隧道
5.8 其他IP技术
6 TCP与UDP
TCP和UDP是传输层的代表协议,他起着承上启下的作用,主要负责将应用的数据包发送到网络层;
6.1 TCP首部
//协议首部
//抓包首部
接下来,我们简单过一下每个字段内容代表含义:
源端口号:
16位,标识发送端应用端口号;
目标端口号:
16位,标识接收端应用端口号;
序列号:
32位,序列号代表了发包的顺序,一般来说,序列号会有计算机程序发送的SYN携带其实的序列号,之后每次发送一个包,序列号=起始序列号+数据发长度,如果没有数据包,默认+1;
确认应答号:
32位,简称ACK seq,标识下一次发送数据包的序列号;
数据偏移:
4位,TCP首部的长度,该字段表示 TCP 所传输的数据部分应该从 TCP 包的哪个位开始计算,当然也 可以把它看作 TCP 首部的长度。该字段长 位,单位为 字节(即 32 位)。不包 括选项字段的话,如图 6.26 所示 TCP 的首部为 20 字节长,因此数据偏移字段可以设置为 。反之,如果该字段的值为 ,那说明从 TCP 包的最一开始到 20 字节
为止都是 TCP 首部,余下的部分为 TCP 数据。
保留:
没有实际含义,用来协议的拓展;
控制位:
8位,每一位从左至右分别为 CWR、ECE、URG、ACK、PSH、RST、SYN、FIN 这些控制标志也叫做控制位。当它们对应位上的值为 时,具体含义如下图所示。
Mark:这些控制位默认为0,如果那个控制位被设置为1,就代表了一些特定的含义;
CWR(Congestion Windows Reduced):
CWR标志与后面的ECE标志都用于IP首部的ECN字段。ECE标志为时,则通知对方已将拥塞窗口缩小。
ECN(ECN-Echo):
ECE标志表示ECN-Echo置为会通知通信对方,从对方到这边的网络有拥塞。在收到数据包的首部中ECN时将TCP首部中的ECE置为 1 。
URG(Urgeant):
表示有紧急的数据需要处理,对于数据细节将会在后续的该指针中解释;
ACK(Acknowledgment):
确认应答位,TCP协议中除SYN包之外都应该被设置为1;
PSH(Push flag):
该位为1时,表示需要将收到的数据立刻传给上层应用协议。PSH 时,则不需要立即传而是先进行缓存。
RST(Reset):
重置位,当这个位设置为1之后,代表TCP连接必须因为一些原因断开连接,详细的解释参考这里:
mp.weixin.qq.com;
SYN:
连接位,当设置为1时,代表建立TCP连接;
FIN:
释放连接位,当设置为1之后,表示数据发送方没有数据发送了,请求断开连接,接收方在收到这个控制位之后,将会在自己处理完所有数据后,断开连接;
窗口大小(Windows Size):
16位,表示当前TCP连接中所能接收的数据大小,TCP协议中不会出现发送大于窗口的数据;
选项:
这个字段出现在TCP连接控制报文中,用于协商上端的能力,常见的几个代表项如下:
类型2:用来确认连接可以发送的报文最大长度;
类型3:窗口扩大;
类型4、5:选择确认应答,TCP标准应答中仅允许一次发送一个数据报文+应答报文,这种模式在网络拥堵的情况下性能会很低,而这个字段可以将应答数量增加到四个数据包,也就是说允许一次接收4个数据包进行一次应答;
类型8:时间戳字段选项,用于高速通信中对序列号的管理。若要将几个 数据高速转发到网络时, 32 位序列号的值可能会迅速使用完。在传输不稳定的网络环境下,就有可能会在较晚的时间点却收到散布在网络中的一个较早序列号的包。而如果接收端对新老序列号产生棍淆就无法实现可靠传输。为了避免这个问题的发生,引入了时间戳这个选项,它可以区分新老序列号。
6.1.1 TCP吞吐量
这个思想也经常用在TCP极限性能测试中,iperf工具提供了一个-P参数,来控制TCP连接;
6.2 UDP首部
UDP相比TCP首部简单了许多,这里我们不在详细描述,读者可以参考TCP部分;
6.3 TCP&UDP的区分
TCP 是面向连接的、可靠的流协议。流就是指不间断的数据结构,你可以把 它想象成排水管道中的水流。当应用程序采用 TCP 发送消息时,虽然可以保证发送的顺序,但还是犹如没有任何间隔的数据流发送给接收端TCP 为提供可靠性传输,实行"顺序控制"或"重发控制"机制。此外还具备"流控制(流量控制) "、"拥塞控制"、提高网络利用率等众多功能。
UDP 是不具有可靠性的数据报协议。细微的处理它会交给上层的应用去完成。在 UDP 的情况下,虽然可以确保发送消息的大小\却不能保证消息一定会到达。因此,应用有时会根据自己的需要进行重发处理。
这就意味了TCP可以在传输层为应用保证可靠的传输,而如果应用使用了UDP协议,就需要应用自身需要进行重发处理;
TCP&UDP区分:
6.4 传输层标识 - 端口号
在第四章我们提到过,IP层包含了一个协议字段,标识他的上一层协议是TCP还是UDP:
//TCP
//UDP
传输层也是如此,他需要一个标识来区分数据包应该发给哪个应用,这个标识就是端口号:
6.4.1 端口号如何确认
1,标准制定的端口号
这部分端口号是固定的,是协议标准组织为一些特定的应用分配,应用程序应该主动避免使用这部分端口号;
2.操作系统分配
动态分配端口号范围是49152 ~ 65535;
TCP&UDP的一些知名端口号分配如下:
//tcp
//udp
6.5 TCP如何实现可靠性传输
6.5.1 通过序列号&确认应答
TCP应用中,发送端向接收端发送数据时,在接收端收到之后,会向发送端回复一个确认代表已经收到,对于发送端来说,如果某个数据包没有收到回复只要重传就可以,而对于接收端,如果反复收到来自发送端的重传数据,这将是灾难性的,如果每次收到数据包都处理显然是不现实的,接收端就要一种机制来确认是否需要接收数据;序列号是发送端顺序发送的每一个数据包的序列号,接收端收到数据包之后,解析这个序列号以及数据长度,并且将二者之和作为自己下一次收包的序列号,这样实现了可靠的传输;
6.5.2 超时重传
超时重传是指发送出去的数据包到接收到确认包之间的时间,如果超过了这个时间会被认为是丢包了,需要重传。那么我们该如何确认这个时间值呢?在一个稳定的网络环境中,一个数据包的收发时间是差不多的,都会有一个类似于平均值的概念。比如发送一个包到接收端收到这个包一共是0.5s,然后接收端回发一个确认包给发送端也要0.5s,这样的两个时间就是RTT(往返时间)。当然,随着网络拥堵等环境的变化,时间会有偏差,如果我们可以设置一个合理的超时门限,也将大大保证TCP包重传的稳定性;
6.5.3 连接控制
TCP是面向连接的协议,双端在发送数据之前,必须进行连接,才可以通信,在通信完成之后主动断开连接,断开连接之后,将不在处理收到的发送端的任何数据包,连接与断开连接流程如下:
6.5.4 TCP以段为单元传输
在此之前我们说过,IP层数据包的传输单元是MTU,在传输层,其最小传输单元是MSS,这个值最理想的情况就是
长度不至于在IP层分包,以此简单分包对于性能的损耗;MSS在TCP建立连接时协商得到,双端在建立请求时分别告诉对端自己的传输单元,然后本次连接将采用最小值进行传输,报文内容如下:
//syn
//ack
6.5.5 滑动窗口
如上一节,我们说到,TCP传输是以段位传输单位,每发送一个段,接收端就需要一次应答,按照这种方式来传输的话,TCP的性能将会大大折扣,为了解决这个性能问题,就引入了滑动窗口的概念,简单来说就是,扩大TCP传输单位,即一次传输多个数据包,同时,接收端也需要进行多次应答,如果其中一个数据包没有收到应答,发送端应该继续保留这部分数据并且进行重传,直到收到应答,再将缓存区这部分数据删除;在TCP协议栈中保留了几个窗口相关的设置:
tcp.window_size_value
tcp.window_size_scalefactor
tcp.window_size
其中tcp.window_size = tcp.window_size_value * tcp.window_size_scalefactor;
几个注意的点:
1.TCP滑动窗口并不是越大越好;
2.发送的窗口 <= 接收端窗口;
3.滑动窗口的大小是需要根据网络拥堵情况动态调整;
4.窗口大小由接收端决定;
窗口控制如何实现高效传输?
(1)减少不必要的重传,在发送单个数据段必须对应收到应答报文的传输过程中,如果丢失了一个数据包,就必须要进行重传,而设置了滑动窗口的传输过程中,如果仅仅丢失了一个数据包,可以根据后续应答报文的序列号进行复判是否需要重传;
如上图,虽然报文段1-1000应答报文丢失了,但是收到了ack-2001,就认为之前的报文都收到了,就不需要进行重传了;
(2)在快速响应重传,在发送单个数据段必须对应收到应答报文的传输过程中,如果发送端没有收到应答报文,只能依赖超时机制进行检测,而在滑动窗口的传输过程中,由于发送端在反复发包,如果中间丢失了一个报文,接收端可以通过应答报文的序列号快速响应,如果连续收到几个ack序列号一致,那么就认为数据丢失,可以快速进行重传,效率相对较高;
6.5.6 流量控制
上一节描述到,为了解决TCP单段传输的性能问题,我们引入了滑动窗口的概念,允许TCP一次发送多个数据包,接收端进行多次确认,那么试想,如果网络环境比较拥堵,发送端在发送多个数据包的时候,丢失了其中几个包,如何保证传输数据的可靠性?如果窗口设置太多,发送端不停的发送数据包,而接收端处理效率低于发送端,造成的流量阻塞如何解决?那么,针对这些问题,我们如何设计高效的传输细节,可以避免呢,本章将会详细解析;
(1)流控制解决网络拥堵问题
接收端的应答报文中(TCP首部)会包含一个窗口字段,这个字段也代表了接收端数据缓存区的大小,这个值越大代表网络的吞吐越大;如果接收端因为环境拥堵或者CPU性能限制,这个值也是逐渐减小,平滑的处理性能问题;
这里两个代表的算法名称就是:
快重传算法:快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。接收方收到了M1和M2后都分别发出了确认。现在假定接收方没有收到M3但接着收到了M4。显然,接收方不能确认M4,因为M4是收到的失序报文段。根据 可靠传输原理,接收方可以什么都不做,也可以在适当时机发送一次对M2的确认。但按照快重传算法的规定,接收方应及时发送对M2的重复确认,这样做可以让 发送方及早知道报文段M3没有到达接收方。发送方接着发送了M5和M6。接收方收到这两个报文后,也还要再次发出对M2的重复确认。这样,发送方共收到了 接收方的四个对M2的确认,其中后三个都是重复确认。快重传算法还规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必 继续等待M3设置的重传计时器到期。由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约20%。
快恢复算法:与快重传配合使用的还有快恢复算法,其过程有以下两个要点:当发送方连续收到三个重复确认,就执行“乘法减小”算法,把慢开始门限ssthresh减半。与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口cwnd现在不设置为1),而是把cwnd值设置为 慢开始门限ssthresh减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。
(2)慢启动算法,发送方维持一个拥塞窗口 cwnd ( congestion window )的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口。发送方控制拥塞窗口的原则是:只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。慢开始算法:当主机开始发送数据时,如果立即所大量数据字节注入到网络,那么就有可能引起网络拥塞,因为现在并不清楚网络的负荷情况。因此,较好的方法是 先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。通常在刚刚开始发送报文段时,先把拥塞窗口 cwnd 设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值。用这样的方法逐步增大发送方的拥塞窗口 cwnd ,可以使分组注入到网络的速率更加合理。
每经过一个传输轮次,拥塞窗口 cwnd 就加倍。一个传输轮次所经历的时间其实就是往返时间RTT。不过“传输轮次”更加强调:把拥塞窗口cwnd所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。另,慢开始的“慢”并不是指cwnd的增长速率慢,而是指在TCP开始发送报文段时先设置cwnd=1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后再逐渐增大cwnd。为了防止拥塞窗口cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量。慢开始门限ssthresh的用法如下:当 cwnd < ssthresh 时,使用上述的慢开始算法。当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞控制避免算法。拥塞避免算法:让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢开始门限ssthresh设置为出现拥塞时的发送 方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生 拥塞的路由器有足够时间把队列中积压的分组处理完毕。如下图,用具体数值说明了上述拥塞控制的过程。现在发送窗口的大小和拥塞窗口一样大。
6.6 Socket编程
应用在使用 TCP UDP 时,会用到操作系统提供的类库。这种类库一般被称为 API (Application Programming Intenace ,应用编程接口)。使用 TCP UDP 通信时,又会广泛使用到套接字 (socket) API 套接字原本是由 BSD UNIX 开发的,但是后被移植到了 Windows Winsock以及嵌入式操作系统中。应用程序利用套接字,可以设置对端的 IP 地址、端口号,并实现数据的发送与接收。