应用层之下有传输层,应用层使用系统调用把数据拷贝到传输层就返回,继续执行自己那一层的代码;传输层使用TCP协议来管理和对端主机传输层之间的交互;应用层将数据传给传输层的TCP,TCP这个传输控制协议根据滑动窗口,选好能发送的数据,传给网络层,网络层有IP协议来管理
TCP的数据、报文,一般情况下只有发送方和接收方能看到且认识,中间的主机最多看到网络层的报文,还有NET帧。TCP收到数据后,向下交付给IP层,IP报文里面包着TCP报文,在网络里传输的是IP报文,IP报文的有效载荷是TCP的报头 + TCP的有效载荷,这也就是封装。
IP协议能很大概率将IP报文从A主机跨网络送到B主机,所以肯定有可能各种原因发送失败,而TCP就是提高成功概率的存在,达到尽量百分百成功。IP执行操作,TCP提供传输策略。TCP发送给IP报文,IP得给应答,如果没有应答,就说明IP报文丢了。所以TCP、IP协议的作用就是将数据从A主机可靠地跨网络送到B主机,这也就是OS做的事。所以这两个会连着叫。
旅游的时候,我们会说要去北京玩,等到了北京,再说去北京玩就奇怪了,这时候就会说要去某个景点。IP地址就是如此,IP地址 = 目标网络 + 目标主机,是4个字节,32个比特位,前16个比特位属于目标网络,后16个比特位是目标主机。
主机是配有IP地址的机器,路由器是配有多个IP地址且能进行路由控制的机器,主机和路由器都属于节点。
IP协议的报头和有效载荷分离是与TCP协议相同的,4位首部长度表示0字节 + 选项长度。8位协议表示有效载荷是什么报文,也就是它的上层是什么。4位版本一般都是IPv4地址,4字节32个比特位,IPv6用6个字节128个比特位来表示地址,6和4不兼容,6和4地址都存在。
TCP协议决定了端口号,IP协议决定了IP地址。
它指的是IP传送的特点。由3位优先权字段(已弃用),4位TOS字段,1位保留字段(必须设置为0)组成,所以就只看4位TOS字段即可。4位TOS分别表示最小延时(最短路径),最大吞吐量(带宽最高,路由器好的),最高可靠性(丢包概率最低的路径),最小成本,四个相互冲突,只能选一个。
IP协议是面向数据报的,向上交付时要一个个包交,收到包时得能把报头和有效载荷分离。16位总长度 - 4位首部长度就是有效载荷长度。
在两个主机之间有很多路由器,如果报文传输时,有路由器出现问题没有传给主机,而是传给了另一个路由器,另一个也不好,它又给了另一个路由器,最后经过多个路由器又回到了最一开始坏掉的那个路由器,那么这就成了环路,并且一直环路,后面再发更多的报文,还会继续环路。网络之中有很多问题可能发生,阻碍了传输,响应时间很长。为了解决这个问题,就有了生存时间。生存时间表示该报文在转发过程中最多经历的路由器的次数,每经历一个,就–,减到0,生命周期结束,就被丢弃,不管到没到达对端主机
就像一个大学,有多个学院,多个专业属于一个学院。学院的编号分成10,11,12,13等开头,这样就区分了多个学院,每个学院的学生都用学院编号 + 一串号码来作为自己的学号,这样每个人学号都不同。当然每个学院内每个专业的学生也可以有限制,比如2000 - 5000之间是计算机专业的学生的号。要找到某个学生,就先找到学院,确定了范围,然后再找到学生。这样查找的过程就是排除的过程,最终锁定到某个范围,提高了效率。
一个学院是一个子网,一个学院学生会主席是路由器,有学生会主席群,能够方便地找到某个主席,这个群就是转发集群,也叫公网。网络传送数据是先找到目标群(子网),再找到目标主机,主机就是学院中的某个学生。学院有很多学生,每个学生都有学号,这就是主机的IP地址。像上面的过程,为了更快速地找到子网,需要把子网划分,也就是学校有多个学院,通过公网,经过路由器去访问子网。之前的IP地址 = 目标网络(网络号) + 目标主机(主机号),即子网 + 主机,这就是子网划分的结果。
学校里,有每个学院学生会主席聚集在一起的群,有每个学院自己的群,学校分为多个学院,学院有学生会主席,这些是由运营商的顶层决定的,也就是现实中中国的移动、联通、电信,韩国的LG U+、KT、SKT。运营商或者网络设备能够合理设置主机号和网络号,就可以保证在相互连接的网络中,每台主机的IP地址不相同。路由器一般会带有DHCP功能,这个功能可以自动地给子网内新增主机节点分配IP地址。
路由器可以连接两个子网,比如一个学院有好多个专业,每个专业都有专业群,专业和学院这两个子网也有路由器相连。这样路由器就得配2个网卡,每个网卡对应一个子网,对应一个IP地址。路由器在相连的多个子网中都是主机,因为网卡的存在,且它通常都是这个子网中编号为1的,因为是子网中的第一台主机。路由器可以构建子网。用手机开热点时,分享给其它人,开热点的手机就相当于路由器。现在的路由器也都支持上层功能,比如应用层的http表单,路由器背面有地址,浏览器登录这个地址,就能进入让用户输入账户密码的网页,这个网页就是之前所说的表单,遵守http协议。
网段的划分通常分为5类
分为A类网和其它,因为第一位不同。7位网络号指会有2的7次方个网络地址,24位主机号指每个网络有2的24次方个主机。ABC常用。现在大部分都申请B类地址,A类网络地址较少,只有2的7次方个,所以很多都不申请A。为了解决这样的问题,引入了CIDR划分方案。引入子网掩码来区分网络号和主机号,子网掩码是一个32位的正整数,前面都是1(会表现255.255.255.0,也就是前24位都是1),直到某个位置开始就全是0,将IP地址和子网掩码进行按位与操作,就得到网络号,网络号和主机号的划分与这个IP地址是哪一类无关。比如192.168.1.1,网络号就是192.168.1.0,主机号就是1。子网掩码1多一些,主机号就少,少一些主机号就大,比如刚才的这个与子网掩码按位与后得到192.168.1.102,主机号就是102,网络号还是192.168.1.0。
运营商划分子网。运营商促进了网络基建的建设。公网中,IP地址只有2的32次方个,所以入网设备就有限。子网的划分不仅仅按国家划分的,还按别的划分,比如地区,人口。
假设每个国家都有自己的IP地址格式,比如固定前8位,中国的前8位是0000 0010,各个国家的运营商都接入自己国家的子网。假设每个国家都有国际路由器,各个国家通过国际路由器连接到一个网,这个就是公网。我们国家有34个省,要包含这个34个省,需要6个比特位,因为5个只能表示32个,那么就可以规定某个省为0000 0010 0000 01…,那么这个省的子网掩码就是这样,每个省都有省的路由器,用于跨省连接,这些路由器也可以构建一个网,这也是公网,这种公网是由国内运营商构建的,全球的公网是由国际运营商构建的。省往下就是市,比如10个市,就可以用4个比特位表示出来,这样前面有14,现在4个,总共18个就是中国某个省某个市的子网掩码,每个市都有市路由器,多个市之间就可以形成一个公网,依次类推。但如果一直按照这样下去,比特位就不够了,所以到了一定级别城市的之后,运营商就构建局域网,开始使用私有IP地址,也就是IPV6地址,可能从地级市就开始使用IPv6地址。一个居民家里的IP地址属于一个县级市,县级市又隶属于地级市。到了开始使用IPv6地址时,IPv4上使用的比特位就减少,转而按规定使用IPv6地址。
运营商对外需要有IP地址。假设已经有了IPv4地址:0000 0010 0000 0100 01…,也就是上面的8 + 6 + 4,不过这里给连起来写了,然后假设后面都是0,那么就是02 04 40 00,换成16进制写出来就是2.4.4.0,这也就是这个省的入口网络,省内的某个IP地址就可以是2.4.4.23。当外国想要访问这个IP地址时,会发现这个不是本国的IP地址,它就交给这个国家的出口路由器,也就是上面所说的省路由器,市路由器,国家路由器,通过出口路由器来到公网,自己国家的出口路由器能找到这个是哪国的IP地址。将2.4.4.23和上面所举例的中国的子网掩码0000 0010(后面都是0)按位与,得到2.0.0.0,发现第一个数字相同,那就是中国境内的IP地址。将2.4.4.23和几个省的子网掩码按位与,直到发现和这个子网掩码0000 0010 0000 01(后面都是0)按位与后,得到2.4.0.0,就继续和这个省的市的子网掩码去按位与,会得到2.4.4.0,再根据23找到最终的目的主机。
具体的划分并不一样,上面的只是大概的思路。实际上,可能会按照ABCD类查找,大地区用A类,小地区用B类。所以明白其大概的做法就好。
根据上述所写,即使在不断找寻目标地址的时候,出现传输丢包,也可以超时重传,都有办法解决。
路由器连接多个子网,所以必然要在它的路由表中保存好各个子网的网络号和子网掩码。因为要拿收到的报文的目的IP和该子网的子网掩码进行按位与,再和自己直连的网络做对比,是就连入这个子网。有多少子网就有多少子网掩码。
子网的划分方案:有IP地址140.252.20.68,有子网掩码255.255.255.0,有网络号140.252.20.0,子网地址范围,也就是IP地址的取值范围是140.252.20.0 ~ 140.252.20.255,也就是说这个子网最多有254个主机。
比如IP地址140.252.20.68,子网掩码是255.255.255.240,按位与得到的网络号是140.252.20.64,子网地址范围就是140.252.20.64 ~ 140.252.20.79,64的比特位就是0100 0000,因为前面4个已经被占用了,所以只能动后4个,后4个从全0到全1,就是0~15,范围就出来,而真正可以用的就是65 ~ 78,因为不能用全0和全1。
127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1。127的报文数据不会发送到网络里,走一遍协议栈,做网络测试。Linux中用ifconfig命令可以看到一个lo:,下面就有inet: 127.0.0.1。
如果都接入公网,IP地址的分配很成问题。IPv4地址时一个4字节32比特位的正整数,总共有2的32次方个地址,将近43亿个,放到现在全球主机肯定不止43亿个,CIDR策略一定程度缓解了不够用的问题,提高了利用率,减少了浪费,但绝对上限仍然不变,还是会到达上限,所以就有了三个办法:动态分配IP地址,NAT技术,IPv6地址。
动态分配采用的是DHCP技术。每次连接上网络,开始用一个主机,设备,路由器就分配一个IP地址。一个IP地址并不会绑定一个设备,用的时候再给地址,不用就让这个地址闲置下来,等待下一个接入网络的设备。
有NAT技术才能有DHCP技术。NAT技术几乎解决了现有的问题,虽然没从根本上解决问题。NAT技术也一定程度上阻拦了IPv6的发展。
IPv4和6不兼容,6也不是4的简单升级版,两者互不相干,IPv6用16字节128位来表示一个IP地址,但IPv6还没有普及。IPv6活跃在内网,很多现在用的软件用的也是IPv6地址。
一个组织,比如学校,单位,要建立局域网,需要遵守RFC 1918规定使用私有IP地址:
10.,前8位是网络号,工16777216个地址
172.16.到172.31.,前12位是网络号,共1048576个地址
192.168.,前16位是网络号,共65536个地址
包含在这个范围内的都成为私有IP,其余则是全局IP,或公网IP。
运营商会在一个地区内用私有IP地址建立子网,建立的方式就像上面从国际到省市的使用公网IP分层分配的方式。私有IP也是从公网IP中截取的一部分,不过这些对于所有的公网IP数来说并不多。
#Linux
ifconfig #出现的第一行的inet就是IP地址,netmask是子网掩码
#Windows
ipconfig
家里拉网时,用光纤连接猫(Modem,调制解调器),猫的另一端连接路由器,设备连接路由器就可以上网。数字转为模拟,模拟转为信号,猫将信号转为路由器可以用的信号,设备就可以使用网络了。每个设备发送网络请求,比如刷视频,看小说,刷新网页等,都经过家里的路由器,再经过运营商的路由器,由运营商路由器决定如何发送。家里的路由器有两个账号,一个是付费账号,用这个账号交费,交上费后再发送请求,运营商服务器检测到这个不是欠费用户,才能让发送,如果欠费,就丢弃报文,并告知欠费,所以运营商是知道这个账号的,这个账号是手机号,也就是家里必须要有一个手机号用来交费,通常交话费来交网费,这体现在套餐中。家里路由器还有一个账号密码,也就是我们到一个没去过的地方连接网络时,需要输入密码才行,这个密码就是这个账号的密码,账号由自己家决定,网络名称也可以改,所以一打开网络连接会看到各种WiFi名称。
如果要登录外网,运营商路由器就检测到请求不合理,非法,就会丢弃报文,所以访问不到,这时候需要用VPN,墙就是运营商路由器。既然我们每次使用网络,都得经过运营商,所以让它不知道就好了,在最一开始发送时就不通过它发送。
我们自己访问一个软件时,会把报文交给运营商服务器,然后发到国内的公网,再找到这个软件厂商对应的服务器地址。家里构建的网络都是私有IP,私有IP可以重复,不过各家通过的运营商路由器可以不同,所以这个方法提高了绝对上限。
当一台主机要访问一个目的IP时,这个目的IP不是现在的子网内,将源IP和目的IP交给家用路由器,这个操作叫缺省路由,然后家用路由器将信息交给自己所属的运营商路由器,这就通过了两个子网,一个是家里的,一个是运营商和各个家用路由器之间的,所以家用路由器才被当做第一个入网设备,因为在运营商路由器看来,它只知道这些家用路由器,家用路由器入网了,家里其它设备才能入网。家用路由器和家里设备构建的子网的IP的LAN口IP,和运营商之间的子网IP是WAN口IP,一个队内一个对外。每个路由器都会检查送过来的信息是否属于它管理的子网,不是就往上交。如果要访问的是公网,那就一直上交到公网,然后去找到对应的服务器去访问。但返回响应的时候有些麻烦,因为源IP是自己设备的IP,这个IP全国有很多重复的,应该发到哪个子网?出现这个问题的根本是私有IP出现在了公网上。为了防止这种现象,私有IP就不能出现在公网。
家用路由器交给运营商路由器时,将源IP换成当前WAN口IP,运营商路由器再继续上交,上交过程中也有转为WAN口IP的操作,这样做的原因就是即使到了公网,也能用过源IP找到对应路由器,将源IP转为LAN口IP,也就能找到自己所管理的子网中的某一个路由器,逐层查找。在内网中,将源IP不断转换的过程就是NAT技术。到了内网后,运营商还有别的办法去找到最一开始发送信息的设备,这个之后再写。把LAN设置成IPv6,WAN设置成IPv4,就可以做到转换解决问题了。
路由在之前的博客中写到过,路由算法暂且不管。路由在收到目的IP后,就按照算法找出最近路线中下一站去哪,就把报文送到指定的下一个路由器,下一个路由器再根据算法找到最近路线中下一站应该是哪个路由器,再把报文送过去。路由器每次计算下一步去哪里时都会拿目的IP去查看路由表。不是每个路由器都知道要怎么发送,但它知道哪个子网的路由器知道,它就把报文推给这个路由器,这样不知道路线的路由器就是默认路由器。当到达目标子网的路由器时,路由器看到目的IP就是它自己的子网,就进入这个子网,然后开始根据端口号找到对应的主机。
路由表可以有route命令查看。
数字那一行就是路由器直连的子网。Genmask是路由器根据特定条目配的子网掩码,Gateway表明下一跳是什么类型。Flags中,U表示正在使用,G表示路由器,default那一行表示和当前主机直接相连的缺省路由器,当主机发送报文时不知如何发送,就交给缺省路由器发送。Iface是OS在网络中形成的网络接口,也就是当报文通过IP地址,子网掩码等找到这台主机时,就通过这个接口来发送到主机上。
最一开始发送报文的设备,最多知道这个目的IP是不是自己这个子网的,不是就交给路由器,从内网到公网,一路都一样,都只知道不是自己子网的,到了公网,也会考虑路由表等,内网的路由器相对简单些。
上图的路由器直连了两个子网,图中两个192开头的,也就是有两个网络接口连到这两个网络。当收到一个目的IP后,就拿这个IP和路由表中的子网掩码们挨个算一遍,如果路由表中有一样的,那就发到那个子网的路由器中,如果都没有,就通过缺省路由器,也就是默认路由器来发送。一个路由器连接自己的子网的IP地址就可以。
链路层中的MAC帧规定单次发送的有效载荷不超过MTU,即1500字节,所以就让TCP的滑动窗口分批次发送,不能一下全部发送,所以IP一次发送就有了限制。如果TCP一下子发送了很大的报文,链路层又不许超过MTU,那么只能IP自己来搞定,所以IP协议引入了分片机制,报头也就有了一个片偏移。分片后由对方的IP层再组装。假设TCP发送了4500字节的报文,那么IP就分为三个,每个都是1500字节,第一个分片的偏移量,也就是在原报文中的偏移量为0,第二个分片偏移量为1500,第三个偏移量为3000。
标识用来区分IP报文,使其不出现重复的IP报文。3位标志是3个比特位,第一位是保留位,意思是现在不用,以后可能会用;第二位是1表示禁止分片,这时候如果IP报文长度超过MTU,IP协议就直接丢弃这个报文;第三位是一个分片标记,如果没有做分片或者现在这个IP报文是最后一个分片,就置为0,如果不是最后一个分片就置为1。
对端主机得到分片的报文后,根据片偏移排序相同标识的报文,就组装了起来。
接收方会收到很多发送方的报文,很多分片都放在了一起,通过看源IP就能分类发送方。收到报文后,片偏移不为0或者3位标志第三位是1,那就是分片了,那就提取标识,去找同表示的报文;如果片偏移为0,就看3位标志的第三位,为1就说明有分片,为0就说明没有分片。一个报文,第3位标志是1,偏移量是0就是开始报文;第3位标志是0,偏移量大于0,就是结束报文;第3位标志是1,偏移量大于0,就是中间的那些报文。如果第3位标志是0,偏移量是0,那就是独立报文,没有分片。
接收方能够很方便地检验是否收到开始报文,结束报文,等收集一遍报文后,通过偏移量进行升序排序,且遍历一下,就知道有没有报文丢失,有哪些报文丢失,因为每一个报文的片偏移 + 1自身报文长度就是下一个报文的起始偏移量。所以接收方能够得到所有的报文。当接收方组装起所有报文后,报头的16位首部校验和会保证这个报头是正确的,再往上交时,TCP有16位校验和,是检验整体报文是否正确的。如果一旦出错,就得回到IP层再去找报文。
TCP对于报文有序号,假如在发送1000,2000,3000报文过程中,1和2报文丢失了,接收方如何确定前面还有没发送过来的报文? TCP在通信之前有3次握手,这个过程中有报文交换,里面就有起始序号。很多发送方发过来报文,必然有序号相同的报文,但源IP不一样,所以都能区分出来。在一个报文没有收全时,是不会向上交付的,如果一个报文发送过程中出了问题,发送方重发,这会出现序号和源IP完全相同的情况,不过这不太要紧,接收方会对两个报文进行比对,看看是不是同一个,选择正确,完整的那个,再上交。
虽然有分片机制,但网络中尽量规避分片。TCP应当控制好报文的量,而不让IP承担责任。TCP给IP报文,IP分片,IP发送的过程中丢了几片,那么对于TCP,如果补发部分,就要知道补发几个,那么TCP的报头就得多加点东西,但补发全部又不够高效,以及涉及到的其它地方也麻烦。如果是UDP发送的,那更不好。另外,分片,对于网络来说,就是发了多个报文,那么就更容易丢包。所以解决分片的问题,不应该让IP这个执行策略的一层去管理,而应该让TCP这个制定策略的一层控制好报文,尽量不要分片,一次性发送。这也就是为什么滑动窗口要分成多个部分来发送而不是一整个发送。
那么TCP应该怎样控制发送的数据?不考虑选项的情况下,最多不超过1500字节,IP协议报头占20字节,剩下就占1480字节,这个1480就是TCP报文的最大大小,TCP报头占20字节,那么最终TCP有效载荷最多不超过1460字节,TCP有效载荷最大字节量就是最大段尺寸MSS。MSS在三次握手时,客户端发送的报文里就有MSS的值1460,而在服务端返回的SYN + ACK应答报文中也有MSS,这是适合当前情况的值,之后客户端再发送给服务端的ACK报文就没有MSS了。
假设IP报文有3000字节,报头有20字节,有效载荷是2980字节。分片也是IP报文,就必须有报头 + 有效载荷,否则无法组装。分片先以总体1500来分,即20 + 1480。先从头开始分割,原始的报头 + 1480字节的有效载荷为一片,这是报头内部的一些数据需要改变,比如16位总长度;接着再往后分出来1480字节,复制报头过去组成1500字节,这时报头的片偏移,3位标志就得改了;然后继续往后按照这样的策略来分。结果是1500(1480) + 1500(1480) + 40(20),然后3个报文就挨个发送就行。但链路层的MAC帧要求不低于46个字节,所以如果不够46个字节MAC帧就会自己填充PAD字段,实际上就填充一些垃圾数据。
结束。