0%

计网相关基础知识

前言

本文旨在介绍计网的相关基础知识,只介绍到网络层之上

  1. 计算机网络概述
  2. 应用层
  3. Socket
  4. 传输层
  5. 网络层

计算机网络概述

​ 计算机网络就是为了解决计算机之间的通信问题。通讯就是指数据的交换,即信息的交换。计算机的世界里,一切信息都是数据。

​ 与计算机网络有关的东西有很多:网线,网卡,路由器,IP地址,TCP,HTTP,FTP等等。这些东西分别对应着计算机网络中的不同层次。层次有不同的分法:

  • OSI模型将计算机网络分成了7层,由上至下分别是:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。因为分的太细,与实际操作时不相匹配的,因此市场上很少使用这种模型。
  • 市场上成功的模型一般是四层或者五层,分成五层比较好理解:应用层、传输层、网络层、数据链路层、物理层。网线属于物理层,网卡属于数据链路层,路由器属于网络层,对应的协议有IP和ICMP协议,TCP属于传输层,HTTP属于应用层等等。

​ 计算机网络分层的原因在于其体系结构太复杂了,按照不同设备的功能划分成不同的层次更易于规范的标准化,而且每一层相对其它层独立且透明,这一层变化了也不影响其他层的工作,更易于维护。透明的含义可以解释如下:计算机网络的每一层之间不需要理解对方是则怎么工作的,我只需要接收下层给我的数据,这个数据符合我定义的数据规范,我解读并处理了该数据后,按照上一层定义的数据格式封装我的数据,并提交给上一层,上一层就能正确接收到我的数据。分层之后,某层的修改不会影响到其他层,举个通俗的例子:IPV4和IPV6是网络层不同版本的协议,但是这两种版本的切换对应用层HTTP是没有区别的,因为不管用IPV4或者IPV6,传给HTTP的数据格式都是一样的。

应用层

​ 应用层协议比较多,每个协议有不同的功能和用法,比如HTTP用于网页内容的传输,FTP用于文件的传输,SMTP用于邮件的传输等。HTTP是做web服务必须了解的知识点,但是内容很多,我单独写了一片博客:HTTP详解

Socket

​ 在应用层和传输层之间有一个接口叫做Socket。Socket不属于某一个层,它可以理解应用层和传输层之间的一个管道,用来连接操作系统和应用层中的具体应用进程,应用可以操作Socket来使用操作系统的网络功能。

​ 因为传输层之下基本都是由操作系统控制,而应用层协议是由应用进程控制,所以要定义一个接口来建立起应用进程和底层协议的桥梁,这个接口的实现就是Socket。大部分操作系统都实现了Socket。

传输层

​ 传输层最经典的两个协议是TCP和UDP,其他的比如DCCP,SCTP本文就不讲了。传输层提供的是应用进程之间的逻辑通信机制。传输层通过Socket提供的端口号,把一个进程的数据传送到另一个进程。

​ 传输层有多路复用的概念,这和物理层中的多路复用不一样,物理层的多路复用是指物理线路上的复用,如:频分复用、码分复用等;而传输层中多路复用是指:多个数据报被同时接收,计算机如何处理这些数据包是如何分发,按照什么原则分发。在传输层之下,所有的数据包都经过了相同的处理,但到了传输层,不同的数据包传输就有了区别。所有其他主机给我发送的所有UDP数据包都会被提交到同一个端口,而TCP数据包会根据其连接的不同分发给不同的端口。因为TCP连接是一对一的,每个端口只对应一个连接,也同时对应发送数据的主机上某个唯一端口,因此如果发送数据的主机想要和我创建多条TCP连接,需要创建不同的进程或者线程,还需要相应的端口号。

UDP

​ UDP只对IP协议做简单的拓展,仅仅只把网络层传输过来的数据区分一下端口号,就递给进程了,有可能也会做一点简单的错误检测。UDP有以下的好处(主要和TCP对比):

  1. 不需要建立连接,因此数据请求的延迟小;
  2. 实现简单,不需要负责实现过程,比如维护连接等;
  3. 头部开销很小,在数据内容之上,只包装了一些区别端口号和差错检验的账号;
  4. 应用层可以很好地对其进行拓展。

​ UDP数据报的结构如下:

​ 可以看到,一个UDP数据报,除了具体的传输数据,还在首部增加了8个字节的数据用来区分端口,限制长度和差错校验。其中这个数据长度是包含了8个字节的头部数据的,可以看出一个UDP的数据包的长度是有限制的,不能太大。UDP的源端口号可以省略,如果省略则代表了我的数据一旦发出去,就不需要回复了;校验和字段也可以省略,不过一般都会做一些简单的校验,防止数据在传输过程中出错,导致数据乱序,残缺。这种数据应用层接受到是无法使用的。校验后这种错误的数据会在传输层废弃,然后给发送源一个ICMP数据包,告知数据错误,然后这个数据传输就结束了,因为UDP不提供重传机制。

​ UDP进行差错检验的方法和IP中的方法一致,这里先不提。UDP的差错检验保证了端口与端口之间正确传输的检测,也能核实出数据部分是否产生了错误。在进行差错检测时,会添加一些额外的数据参与计算,这些数据计算完之后就丢弃了,真正用来传输的数据格式还是上面那个。伪首部结构如下图红色的部分:

TCP

TCP是一个点到点(端口到端口)的协议,是一个可靠的,按序字节流的协议。是一个面向连接的协议。

接收方和发送方都会有一定的存储空间用来缓存数据,一般用于重传,分组重组等功能。

面向连接的含义:通信前必须建立连接,两端维护连接,中间节点不连接。

TCP提供了可靠的数据传输,流量控制和拥塞控制。

可靠的数据传输

​ TCP实现可靠的数据传输主要是基于一种确认(acknowledge,ACK)机制。简单说来就是,我发你一个数据包,你得告诉我你收到了,不然我默认你没收到,等一段时间后就会重新发这个数据包给你,直到你告诉我你收到了。这是保证可靠传输的逻辑。

​ 在可靠传输的具体实现中,TCP采用的是累加确认,确认的是数据中的自己号,而不是确认收到了第几个数据包。正因如此,TCP才被叫做按序字节流的协议。

​ 在TCP发出报文后,如果没有收到确认,要过多久才会重新发送数据呢?计算超时时间有一个算法,里面最主要的参数是RTT(Round Trip delay time),RTT指我发出一个报文开始,到我接受到ACK报文所经过的时间。根据历史值的平均数,和上一个数据包的 RTT 值,经过加权计算之后的值设置为当前数据报的超时时间。这样结合了当前网络和历史网络的状况后得到的结果最合理。如果我发过了一个报文,过了超时时间,就会重新发。因为等待ACK报文需要时间,一个个发报文严重影响传输效率,因此TCP一般都一段段发:TCP有一个滑动窗口机制,一段一段的发送数据,确认时只按收到了第几个字节数(可以理解成下一个报文的头位置)来确认。这一过程中会遇到这样的问题:第五段报文丢失了,第六段、第七段和第八段报文被接收了,接收方因为没有收到第五段报文,因此在收到第六段报文时,接收方会发一个第五段报文的ACK报文,然后又收到了第七段报文,没办法,只好再发一次第五段的ACK,然后又收到了第八段报文,只好再发一次第五段报文ACK,至此,接收方连续发送了三次第五段报文的ACK,发送方立刻重发第五段报文,这就是快重传机制,可见快重传不需要等待计时器超时。一般设置了3次重复ACK报文就会启动重传,因为如果丢包,必然会有两次以上的ACK,但是如果只收到了两次ACK,则很有可能是乱序造成的,这时候重传解决不了问题,详见TCP 快速重传为什么是三次冗余 ACK,这个三次是怎么定下来的?

流量控制

上面讲到TCP的有一个滑动窗口机制。接收方也有一个缓存窗口。如果数据的读取很慢,但是网速却很快,数据大量集中,超过了接收方缓存的大小,这时候即使再来数据,也无法接收,于是接收方就不停地发送缓存窗口最后一个位置的ACK,然后发送方就会不停地进行重传,这大大浪费了网络资源。因此,接收方每次返回ACK报文时,会在报文中加入缓存空间的剩余量是多少,发送方根据剩余量的多少发送数据。这里有一个边界问题:如果接受方的ACK报文中剩余量为0时怎么办?肯定不可能停止发送数据,因为停止发送就再也不知道剩余缓存量的变化了。因此,如果接收方缓存剩余量为0,发送方会间歇性、尝试性地发送一组探测报文(ZWP),探测一下对方还有多少余量,如果余量变多了就恢复数据的传输,这就实现了TCP的流量控制。

拥塞机制

TCP采用的是端到端的控制方法,由两端的计算机控制,中间的路由不提供明显的控制。TCP的拥塞控制中有多种算法。目前TCP的拥塞控制流程一般是这样的:

  • 最一开始,采用慢开始算法,发送窗口的大小成指数上升到某一阈值。举个例子,窗口大小依次为:1,2,4,8,16,32,64(阈值ssthresh,假设这个值是64)
  • 到达阈值后,采用线性增算法(拥塞避免),发送窗口的大小每个时间点增加一:64,65,66,67….。
  • 这时候会出现两种情况
    • 当增加到80时,发送方连续收到三个相同的ACK:立刻将发送窗口大小设为40(减一半),并将阈值也设置成40,随后线性增加发送窗口大小的算法。这就是快恢复
    • 当增加到80时,发送方发现一个数据包超时了(也就是没有收到接收方的ACK报文),立刻把发送窗口的大小设置成1。
    • 解释
      • 第一种情况要么是乱序,要么是丢包,不管是那种,数据包都是能够传输进来的,网络很通畅,因此可以指定快恢复。
      • 第二种情况直接超时了,说明网络质量很差,这时候需要降低发送速率,防止阻塞。

为什么TCP有拥塞控制?因为其有重传机制,网络环境差就会不停地重传,造成阻塞,而UDP不依赖于网络环境,丢了就丢了。

TCP报文

由上至下依次解释如下:

  • 1、源端口号:数据发起者的端口号,16bit
  • 2、目的端口号:数据接收者的端口号,16bit
  • 3、序列号:32bit的序列号,真正发送数据时使用,告知当前发送的一段数据的首字节的序列号,如果发的报文不含数据(如确认报文),此字段是没有变化的。若 SYN=1 或 FIN =1 的数据报当作含有一字节数据。
  • 4、确认序列号:32bit的确认号,是接收数据方期望收到发送方的下一个报文段的序号,因此确认序号应当是对方刚刚发给你的 TCP 报文中的序号字段加数据长度的值再加1,是你的确认序号,你要回复他说,我收到你的数据了,所以要确认的是对方的序号。
  • 5、首部长度:4位,最大可表示的数为 15 。而光首部就有 20 字节,所以在这里规定,每个 1 代表 4 字节,就是上图中的一行,这个字段值为几,就是几行。最大可表示 15*4 = 60 字节。
  • 6、保留:6bit,均为0
  • 7、紧急URG:当URG=1时,表示报文段中有紧急数据,应尽快传送,紧急指针字段有效。
  • 8、确认比特ACK:ACK = 1时代表这是一个确认报文,取值 0 则不是确认报文;
  • 9、推送比特PSH:当发送端PSH=1时,接收端尽快的交付给应用进程;
  • 10、复位比特(RST):当RST=1时,表明TCP连接中出现严重差错,必须释放连接,再重新建立连接;
  • 11、同步比特SYN:在建立连接是用来同步序号一个报文中 SYN=1,ACK=0时,是表示这一个连接请求报文段。SYN=1,ACK=1时表示的是接收方同意建立连接。
  • 12、终止比特FIN:FIN=1时,表明此报文段的发送端的数据已经发送完毕,并要求释放传输连接。
  • 13、窗口:就是提供流量控制的功能,表示可缓存字节数的多少。
  • 14、校验和:该字段检验的范围包括首部和数据这两部分。由发端计算和存储,并由收端进行验证。
  • 15、紧急指针:紧急指针在URG=1时才有效,它指出本报文段中的紧急数据的字节数。
  • 16、选项:长度可变,最长可达40字节。绝大多数不适用此字段,也就是说 TCP 绝大部分是 20 字节。

TCP连接

TCP是面向连接的,双方进行数据交换前必须建立连接。TCP的连接机制就是注明的三次握手,四次挥手。

三次握手

讲握手机制之前必须明确一个概念。序列号,用来标志我发送数据的第一个字节的序号。在建立连接前,会根据计算机的时钟信号初始化一个序列号,这个序列号是操作系统计算出来的(防止有人伪造连接)。目前我还没有发送数据,所以TCP头部信息中的序号的值就是初始值。

  • 发送端发起连接请求:向接收端发起一个请求连接的TCP报文,初始化一个序号x,SYN = 1, ACK = 0。
  • 接收端收到连接请求,发起一个同意连接的TCP报文:接收端也会初始化一个序号y,SYN = 1, ACK = 1(同时确认序列号为:x + 1,可以简写成 ACK = x + 1)
  • 发送端也发送了一次ACK,告知接收端我收到了你的同意:ACK = 1(确认序号为:y + 1,简写成 ACK = y + 1)

​ 两台主机都有自己的序号,建立连接的过程就是相互确认对方的序列号,从而在交换数据的时候保证有效。确认序号要确认的是期望得到的下一段报文的序号。

​ 为什么需要三次握手呢?发送方如果发送了一条请求连接的报文A,但是因为网络问题超时了,此时发送端会重新再发一条请求B,这两条请求的序号是不一样的,此时如果接收方返回了一个同意连接的请求C,这个C的确认序号是基于A报文的序号的,如果此时接收方建立了连接,那就是B和C建立了连接,此时序号对不上,那么数据传输就会失败。此时引入了三次握手,如果接受方收不到C报文的ACK,就不会建立连接。

四次挥手

  • 我准备断开连接了,此时发送一条请求断开连接的TCP报文:FIN = 1, seq = x + 2,ACK = 1(ACK = y + 1)。
    • 官方文档规定,除了建立连接,任何时候ACK都要是1
    • 我一旦发出了FIN报文,我就不会再发送有数据的报文了
    • 这里seq是x+2主要是为了与图片一致
  • 你收到了我的FIN报文,回复一个ACK,同意断开:ACK = x + 3
    • 此时,你虽然应答了我的断开连接报文,但是你仍可以继续传输数据。比如你的数据还没有穿完我就发给你一个断开连接的报文,如果你没有传完数据,是可以继续一直传的。
  • 你传完了数据,发我一个FIN:seq = y + 1
  • 我收到了你的FIN,发送一个ACK:ACK = y + 2
    • 此时你如果收到了我的ACK,就可以立刻释放连接了
    • 我不能释放连接,因为我不确定你有没有收到我的ACK,因此我需要等一段时间再释放(数据包最大存活时间的两倍:2MSL)

注意:

  1. 收到我的FIN之后,如果你没有要传给我的数据,那么你就直接返回个FIN给我,这样就简化成了三次挥手。

  2. 为什么要四次挥手?要么保证发送方能够正确释放连接,要么保证接受方能够正确释放连接,少一个都不行。

  3. 为什么要等待2MSL,超过2MSL后,连接中的所有报文会自动丢弃,这样我释放连接再建立了新连接后,可以保证没有旧的报文。

网络层

​ 网络层的核心功能是转发路由。因为要实现路由和转发功能,所以这一层实现了很多路由协议,要实现转发,就需要知道转发地址,这用到了IP协议。IP协议中规定一些寻址规则,以及数据报过大时如何切成一小片一小片的问题等。此外,网络层还包括重要的 ICMP 协议,依托于这种协议的数据都像是网络中的指令,计算机或者中间路由设备就成为了官兵的角色,根据指令内容做出相应的动作反应。

IP地址

基础知识科普

​ IP地址是有限的,只有32bit,所以要对其进行划分,比如中国一部分,美国一部分。划分大块后还要继续划分,划给省、市、学校等等。这个划分过程,称为划分子网。于是就规定了,IP地址是有两个部分组成的网络号和主机号。网络号的位置是不确定的,如果一个子网很大,网络号就小,主机号就可以很多。

​ 以前会把IP地址划分成A,B,C类,还有划分子网的概念,将主机号中的一部分拿出来作为子网号:IP = 网络号 + 子网号 + 主机号。要使用子网必须使用子网掩码,一个B类地址默认的子网号是255.255.0.0,如果他的子网占两个比特,那么他的子网掩码就是11111111.11111111.11000000.00000000 = 255.255.192.0。外部网络是看不见子网的。

​ 现在划分子网的方式是CIDR(无类域间路由),形式是 x.x.x.x/n,例如:202.113.132.45/24,这表示前24位是网络号,后8位是主机号。

​ 这里列举一些特殊的网络地址:

​ 以上特殊的网络地址有可能会碰到,放在这里记录一下。

​ 还有一些是私有的网络地址,一般是自己的内部局域网访问,比如校园网什么的。如下图所示:

IP数据格式

​ 从传输层传来的TCP或UDP的段需要在网络层增加一个首部,然后在提交给数据链路层。网络层对数据作了些什么呢?首先网络层具有转发的功能,因此必须要知道数据的目的地,于是网络层对数据增加了目的地址,这个目的地址就IP地址,唯一地标识一台主机。网络层还会对超过MTU(Max Transfer Unit最大传输单元)的数据包进行分片。以太网的MTU是1500字节,这是经验的规定,因为如果MTU设置的太小,数据包被切成很多快,传输的错误率就会上升,不利于数据的传输;切的太大,又会增加传输的延迟。

​ IP数据报的结构如下:

  1. 版本 4bit 指 IP 协议的版本。目前广泛使用的 IP 协议版本号为 4 ,IPv6,版本号为 6 。

  2. 首部长度 4bit 单位是 4 个字节( 32bit 也就是上面的一行。因为 4bit 最大描述的数值是15,首部长度最短也需要20字节,不够描述的,所以单位改成 4 字节),那这里的值一般为 5 。首部长度也就是 20 字节。首部长度大小取值范围 20 字节到 60 (4*15)字节,首部长度一般都是 20 字节。当 IP 分组的首部长度不是 4 字节的整数倍时,必须利用最后的填充字段加以填充。因此数据部分永远在4字节的整数倍开始。

  3. 区分服务 8bit 目前几乎不使用,若要支持区分服务,需要中间所有的路由器都支持区分服务,但是目前的绝大多数路由器都不支持,所以区分服务几乎不使用了。

  4. 总长度 16bit 首部长度 + 数据长度,单位是字节。数据报的最大长度为 2^16-1 = 65535 字节。但由于数据链路层的最大传送单元 MTU < 65535,所与当一个数据报封装成链路层的帧时,此数据报的总长度(即首部加上数据部分)一定不能超过下面的数据链路层的MTU值,若超过则需要分片(因此有上图的第二行,用于切片)。

  5. 标识 16bit 软件在存储器中维持一个计数器,每产生一个数据报,计数器就加1,并将此值赋给标识字段。但这个“标识”并不是序号,因为 IP 是无连接服务,数据报不存在按序接收的问题。当数据报由于长度超过网络的 MTU 而必须分片时,这个标识字段的值就被复制到所有的数据报的标识字段中。相同的标识字段的值使分片后的各数据报片最后能正确地重装成为原来的数据报

  6. 标志 3bit 目前只有2位有意义。标志字段中间的一位记为 DF (Don’t Fragment),意思是“不能分片”。只有当DF=0时才允许分片,若为 1 则不分片。标志字段中的最低位记为 MF (More Fragment)。MF=1即表示后面“还有分片”的数据报。MF=0表示这已是若干数据报片中的最后一个。

  7. 片偏移 13bit 当一个较长的 IP 数据报在分片后,分片后的某一片的第一个 bit 在原分组中的相对位置。也就是说,相对传输层数据报的数据部分的起点,该片从何处截断的。片偏移以 8 个字节为偏移单位。这就表明,每个分片的长度也一定是 8 字节( 64位 )的整数倍。那为什么 ipv4 片偏移量以 8 字节位单位呢?如果直接用字节为单位,总长度是 16bit 而片偏移量只有 13 bit,就会出现不够描述的。 所以偏移量就按 8 字节为单位的来规定了。

  8. 生存时间 8bit TTL( Time To Live ) 就是说 IP 数据报最大能经过多少个路由器跳转(每经过一个路由器,TTL减1)。防止数据报在网络中因为某些错误导致无限循环,浪费网络资源。那么可以知道,路由器在转发时会将这个字段的值减 1,并重新计算首部校验和。

  9. 协议 8bit 标志此数据报携带的数据是使用协议类型( 例如TCP、UDP等 ),以便使目的主机的 IP 层知道应将数据部分上交给哪个处理过程。

  10. 首部检验和 16bit 注意这个字段只检验数据报的首部,不包括数据部分。这是因为数据报每经过一个路由器,路由器都要重新计算一下首部检验和(因为生存时间、标志、片偏移都可能发生变化,就是说在中间路由被重新分片时会出现变化。),不检验数据部分可减少计算量。

  11. 源IP地址 占32位。

  12. 目的IP地址 占32位。

DHCP

​ 我们自己电脑的IP地址有两种方式,第一种是直接设置一个固定的IP地址,需要配置一系列信息,比如子网掩码和DNS服务器地址等等;第二种是自动获取IP地址,这就是DHCP(动态主机配置协议)。通过本网络中的DHCP服务器发出请求,DHCP看看自己还有哪些IP地址没有分发出去,随机挑选一个给你用,返回给你的数据包中不仅包含了IP地址,还有子网掩码,默认网关地址以及DNS服务器地址。

​ DHCP的好处就是方便,以及节省资源,插上网线就能用,不用了之后,这个IP就给别人用。

DHCP索要IP地址的流程

  1. 想上网的设备要先在本网络中广播一个DHCP的报文,看谁回应,谁就就是DHCP服务器。这个过程称之为发现报文。
  2. DHCP服务器在自己身体里找一个合适的IP地址,向全体广播提供一个提供报文
  3. 上网的设备收到IP地址后会发一个请求报文,告诉DHCP服务器收到了IP地址。
  4. 随后DHCP服务器发送一个确认报文,并更新自己的数据库。

​ 这样做的原因是因为网络中可能有很多的DHCP服务器,这些服务器接收到了设备的DHCP报文,都会提供一个包含IP地址的报文,但是设备自己只能接收一个IP地址,所以要设备要发送一个请求报文来与告知其中某一个DHCP服务器“我用了你的IP”,这样这台DHCP服务器才会更新其数据库,其他的DHCP服务则会收回其分发的IP地址。

​ 具体通信过程如下:

  1. DHCP服务其的默认端口是67
  2. 联网设备发送 DHCP 报文的默认端口是 68
  3. 发现报文:源 IP 0.0.0.0:68 目的 IP 255.255.255.255:67 双方都不知道彼此的 IP 地址 所以都是广播通信
  4. 提供报文:源 IP x.x.x.x:67 目的IP 255.255.255.255:67
  5. 下面就是再发一个请求报文和确认报文了

DHCP特点

  1. 在应用层实现,通过应用进程实现
  2. 使用 UDP
  3. 使用了 IP 广播

ICMP

与 IP 息息相关。它的主要功能有差错报告和网络探测俩种。差错报告就是数据在网络中进行转发时,可能会出现一些错误,比如,数据报经过路由器时发现 TTL=0,那么路由器就会丢弃该报文,然后向发送端发送一个 ICMP 报文。而网络探测的功能,最常用的就是 ping 工具呢,这个 ping 工具基于的就是 ICMP 的回声请求应答报文,属于 ICMP 中的一种报文格式。具体的就不细说了。

参考文献

  1. 计算机网络知识解析
  2. CS-NOTE