网络接口基础

学习目标

  • 了解TCP/IP构成和作用
  • 理解接口及接口测试的相关概念
  • 熟悉HTTP协议和接口规范
  • 掌握接口测试流程
  • 熟练掌握如何解析接口文档

1. OSI参考模型

国际标准化组织ISO为了使网络应用更为普及,推出了OSI参考模型,即开放式系统互联(Open System Interconnect)模型。 其含义就是为所有公司使用一个统一的规范来控制网络,这样所有公司遵循相同的通信规范,网络就能互联互通了。

2. OSI的七层框架

OSI模型定义了网络互连的七层框架(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层),每一层实现各自的功能和协议, 并完成与相邻层的接口通信。OSI模型各层的通信协议,大致举例如下表所示:

3. TCP/IP协议与七层OSI模型的对应关系

TCP/IP协议是Internet互联网最基本的协议,其在一定程度上参考了七层ISO模型。 OSI模型共有七层,这显然是有些复杂的,所以在TCP/IP协议中,七层被简化为了四个层次。 TCP/IP协议常被视为是简化过后的七层OSI模型

  • 应用层:主要协议有HTTP、Telnet、FTP、SMTP等。是用来读取来自传输层的数据或者将数据传输写入传输层
    • 应用层包括所有和应用程序协同工作,并利用基础网络交换应用程序的业务数据的协议。 一些特定的程序被认为运行在这个层上,该层协议所提供的服务能直接支持用户应用。 应用层协议包括HTTP(万维网服务)、FTP(文件传输)、SMTP(电子邮件)、SSH(安全远程登陆)、DNS(域名解析)以及许多其他协议。

  • 传输层:主要协议有UDP、TCP。用于实现端对端的数据传输
    • 传输层的协议,解决了诸如端到端可靠性问题,能确保数据可靠的到达目的地,甚至能保证数据按照正确的顺序到达目的地。 传输层的主要功能大致如下:
      1. 为端到端连接提供传输服务
      2. 为端到端连接提供流量控制、差错控制、QoS(Quality of Service)服务质量等管理服务
      3. 这种传输服务分为可靠和不可靠的,其中TCP是典型的可靠传输,而UDP则是不可靠传输
        • TCP协议是一个面向连接的、可靠的传输协议,它提供一种可靠的字节流,能保证数据完整、无损并且按顺序到达。 TCP尽量连续不断地测试网络的负载并且控制发送数据的速度以避免网络过载。另外,TCP试图将数据按照规定的顺序发送。 总体来说,TCP协议传输效率低,但可靠性强
        • UDP协议是一个无连接的数据报协议,是一个“尽力传递”和“不可靠”协议,不会对数据包是否已经到达目的地进行检查,并且不保证数据包按顺序到达。 总体来说,UDP协议传输效率高,但可靠性略低。适用于传输可靠性要求不高、体量小的数据(比如QQ聊天数据)

  • 网络层:主要协议有ICMP、IP、IGMP。主要负责网络中数据包的传送等
    • 简单来说,网络层负责将数据传输到目标地址,目标地址可以是多个网络通过路由器连接而成的某一个地址。 另外,网络层负责寻找合适的路径到达对方计算机,并把数据帧传送给对方, 网络层还可以实现拥塞控制、网际互连等功能。网络层协议的代表包括:ICMP、IP、IGMP等

  • 链路层:主要协议有ARP、RARP。通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡,它们一起处理与传输媒介(如电缆或其他物理设备)的物理接口细节
    • 链路层有时也称作数据链路层或网络接口层,用来处理连接网络的硬件部分。 该层既包括操作系统硬件的设备驱动、NIC(网卡)、光纤等物理可见部分,还包括连接器等一切传输媒介。 在这一层,数据的传输单位为比特。其主要协议有ARP、RARP等

4. 网络的形成

通信的原始时代

很久很久之前,你不与任何其他电脑相连接,孤苦伶仃。只能自己跟自己玩单机

直到有一天,你想找个说话的人。希望与另一台电脑 B 建立通信,于是你们各开了一个网口,用一根网线连接了起来

有一天,一个新伙伴 C 加入了,但聪明的你们很快发现,可以每个人开两个网口,用一共三根网线,彼此相连

随着越来越多的人加入,你发现身上开的网口实在太多了,而且网线密密麻麻,混乱不堪。而实际上一台电脑根本开不了这么多网口

于是,聪明的你们发明了一个中间设备,你们将网线都插到这个设备上,由这个设备做转发,就可以彼此之间通信了, 本质上和原来一样,只不过网口的数量和网线的数量减少了,不再那么混乱。

你给它取名叫集线器,它仅仅是无脑将电信号转发到所有出口(广播),不做任何处理,你觉得它智商低的,因此把人家定性在了物理层

那么你遇到了个问题:集线器收到一条网络讯息,会无脑转播给其他所有电脑,你自己每天也会收到一大堆不属于自己的信息。怎么解决呢?

你机智地决定,给每一台电脑都取一个代号,发网络消息的时候把对方的代号给捎上就行了,只要这个代号全世界唯一,信息就不会发错人。 你给这伟大的发明取了一个高大上的名字叫MAC 地址

你给自己取的MAC地址为:aa-aa-aa-aa-aa-aa

你好兄弟取的MAC地址为:bb-bb-bb-bb-bb-bb

这样,A 在发送数据包给 B 时,只要在头部拼接一个这样结构的数据,就可以了

好兄弟B 在收到数据包后,根据头部的目标 MAC 地址信息,判断这个数据包的确是发给自己的,于是便收下

其他兄弟CDE 收到数据包后,根据头部的目标 MAC 地址信息,判断这个数据包并不是发给自己的,于是便丢弃

后来,你又思考,虽然信息是发对人了,但是原本只要发给电脑 B 的消息,现在却要发给连接到集线器中的所有电脑,这样既不安全,又不节省网络资源。

想着,如果把这个集线器弄得更智能一些,只发给目标 MAC 地址指向的那台电脑B,就好了

苦思冥想之下,你又发明了天才交换机! 它比集线器多了这一点点区别,但看起来似乎有智能了。你把它放在了另一个层级,数据链路层

你是这样设计的:交换机内部维护一张 MAC 地址表,记录着每一个 MAC 地址的设备,连接在其哪一个端口上

有了这张表,现在你想给电脑B发数据,就可以从指定的1号端口出去了!解决了这个问题,你很开心!

为了庆祝,你给这样传输方式而组成的小范围的网络,取名叫做以太网

那这张表是怎么维护的呢?怎么初始化?又怎么添加新的地址对应关系进来呢?你理了一下思路:

  • 第一步:初始化一张空表
  • 第二步:当电脑A(MAC地址为:aa-aa-aa-aa-aa-aa)发消息时,发现A的消息是从4号端口进入的,于是记录一条数据:“MAC地址为:aa-aa-aa-aa-aa-aa”→“端口:4”
  • 第三步:电脑A是给电脑B(MAC地址为:bb-bb-bb-bb-bb-bb)发的消息,由于表里没有对应的电脑B记录,于是就开始广播式发消息,给全体电脑都发送消息
  • 第四步:其他电脑发现不是给自己的消息就拒收了,只有电脑B留下了消息并做出了响应。响应的数据从1号端口进入,于是记录一条数据:“MAC地址为:bb-bb-bb-bb-bb-bb”→“端口:1”
  • 只要重复1~4步,慢慢地MAC 地址表就会越来越完善,就不用再广播式地发消息了!真棒!

因为你的发明被大众所喜欢,越来越多的电脑加入了这个以太网,这时候你发现一个交换机的端口也不够了。

灵机一动,只要每个小区域都有一个交换机,让交换机连接交换机,就能OK啦!

这种规则真的很巧妙。来看看电脑A是如何把信息给电脑F的:

  • 第一步:电脑A发出消息,目标MAC地址的电脑F(MAC地址为:ff-ff-ff-ff-ff-ff)。消息先到了“左侧交换机”
  • 第二步:左侧交换机发现表里面没有电脑F记录,于是又把消息从其他端口广播出去
  • 第三步:右侧交换机收到了广播的消息,它内部的表里有电脑F的记录,是在3号端口。那消息就直接从3号端口出去送达给了电脑F
  • 第四步:电脑F收到信息,向右侧交互机发出了响应,右侧交换机就向左侧交换机发出响应
  • 第五步:左侧交换机在6号端口收到响应,于是记录一笔“MAC地址为:ff-ff-ff-ff-ff-ff”→“端口:6”
  • 只要重复以上步骤,最终在左侧交换机里会记录:电脑EFGH都在6号端口

最后,两张交换机的MAC 地址表就会变成下面这样:

这样的设想足够你和你的朋友们可以愉快地玩一阵子了。但是,人是贪婪的动物,没多久,电脑的数量就发展到几千、几万、几十万

这下好了!交换机已经无法记录如此庞大的映射关系了...

你苦想了一晚上,终于想到了问题所在,那就是“那条红线另一头不知道会有多少设备加入进来”,所以导致了你的表不知道会有多庞大!

那如果专门找一个设备,这个设备也有唯一的MAC地址,把它连在红线的另一头。这个设备只干一件事:记录MAC地址,顺便帮忙转发一下消息。专人专岗,这样问题就解决了!

这个设备,你把它取名为传说中的路由器

因为它的能记录MAC地址,还能转发数据信息,你把它放在了网络层!

之前已经吃过不够存的亏了,这次你想更快升级!于是,你认为一台路由器只有一个MAC地址是不够的,要路由器的每个端口都设定一个独立的MAC地址

你在脑子里预测了一下,路由器里的MAC表可能会变成下面这样:

也就是说,交换机1收到的地址如果不是“AAAA”或“BBBB”的话,会一股脑丢给路由器,交换机2也同理。

你转念一想,觉得这种反推法不够高端,想着:如果“AAAA”和“BBBB”有相同的标志,“CCCC”和“DDDD”也有相同的标志,你就可以通过这个标志来决定要不要把信息丢给路由器了

那这个标志是什么呢?没多久你就想到了!给个编号当标志吧!

因为计算机最底层的语言是二进制的0和1,你刚开始设定的IP地址是32位的二进制编号,就像下面这个:

11000000101010000000000000000001

数字好多啊!记不住!这样吧,四八三十二,每八个数字为一组,共划分成四组,每组之间用一个点分割,这样就好记多了:

11000000.10101000.00000000.00000001

可是,这数字还是太多了,脑瓜子记不住,干脆把二进制变成十进制吧:

192.168.0.1

给这串数字取个名字吧!神奇又伟大的发明再一次诞生!这个名字叫IP地址!!

现在,每台电脑都有一个全球唯一的MAC地址,同时还有一个跟路由器通讯的IP地址,一下子就完美了起来~

这时候传输信息的时候,除了对方的MAC地址,还得加上IP地址。

假设:电脑A给电脑B发消息,因为连接了同一个交互机,它们的消息变成下面这样:

又假设:电脑A给电脑C发消息,消息需要先走到路由器:

再从路由器走向电脑C:

说到这,很多小伙伴其实还是没看出来,为什么有了IP地址,就能判断什么消息要丢给路由器,什么消息丢给自家交换机。

那是因为,你忘记解释另外两个小发明了,那就是子网子网掩码

先来解释一下子网的作用吧

  • 如果源 IP 与目的 IP 处于一个子网,直接将包通过交换机发出去
  • 如果源 IP 与目的 IP 不处于一个子网,就交给路由器去处理

好,那现在只需要解释,什么叫“处于一个子网”就好了

  • 192.168.0.1 和 192.168.0.2 处于同一个子网
  • 192.168.0.1 和 192.168.1.1 处于不同的子网

换句话说,由192.168.0.XXX这种格式组成的,那就是处于同一个子网啦!对!但这是人为的理解。电脑自己也有它的理解。

电脑认为,要通过子网掩码来做个小计算来判断:

比如:有一台电脑的子网掩码是“255.255.255.0”,那么它发信息给别的电脑时,就会开始打小算盘:

  • 源 IP 与目的 IP ,分别与子网掩码进行“与”运算,如果运算结果相等,那就在同一个子网
  • 源 IP 与目的 IP ,分别与子网掩码进行“与”运算,如果运算结果不相等,那就不在同一个子网
“与”运算:把IP和子网掩码全都转换成二进制的0和1,那么:
192.168.0.1    →11000000.10101000.00000000.00000001
255.255.255.0→11111111.11111111.11111111.00000000
数据按照位数进行比对,有0则0,全1则1,得到:11000000.10101000.00000000.00000000
最后再转换成十进制:192.168.0.0

就像下面这样:

  • A电脑:192.168.0.1 & 255.255.255.0 = 192.168.0.0
  • B电脑:192.168.0.2 & 255.255.255.0 = 192.168.0.0
  • C电脑:192.168.1.1 & 255.255.255.0 = 192.168.1.0
  • D电脑:192.168.1.2 & 255.255.255.0 = 192.168.1.0

由此可知道,A电脑和B电脑处于同一个子网;C电脑和D电脑处于同一个子网

也就是说,只要跟自己不是同一个子网的消息,全都丢给路由器就行了,让路由器自己根据MAC地址表去转发消息

咦?A电脑知道交换机在哪,可它怎么知道路由器在哪呢?

其实,只要在A电脑上设置一个默认网关就可以了

因为当初发明路由器的时候,也给他配备了MAC和IP,只要A电脑的默认网关指向路由器的IP就万事俱备!

说把A电脑的消息发给路由器是不准确的,正确的说法是:把A电脑的消息发给“默认网关”。至于默认网关的另一头究竟是什么,A电脑并不关心。

所以,A电脑给自己配置了一个默认网关的IP,作用是把不是自己子网的消息,发给这个默认网关IP

消息总算能发到路由器了,接下来该路由器转发给目标电脑了,它又怎么知道目标电脑在哪?

原来,你早就给路由器设置了一个路由表

这个路由表怎么形成的,一时半会说不清,只要知道它的作用就行了。它就像是MAC表,记录了IP+子网掩码=对应端口,如下图:

你觉得子网掩码这样写太麻烦了,于是给了它一个缩写,如下图:


“192.168.0.0/24”代表的含义:把“192.168.0.0”拆成4段,分别是“192”、“168”、“0”、“0”
每一段转成二进制都是8位,“/24”的意思就是取前24位,三八二十四,也就是要前三段

这就好理解了,路由表里其实记录的是:

  • 192.168.0.xxx 这个子网下的,都转发到 0 号端口
  • 192.168.1.xxx 这个子网下的,都转发到 1 号端口

还没完呢!刚刚神一般的操作都处于“网络层”,网络层的另一边是“数据链路层”。想要链路层继续把数据传给目标主机,还需要主机的全球唯一标识“MAC地址”才行。

可是,链路层只有IP,没有MAC地址。咋整?

那还不简单,只要把MAC地址和IP一起从网络层 传递给 数据链路层,让它也拿个文件来存着就行了!

是的!MAC地址和IP就这么到了数据链路层,这种传递方式没有多高大上,取个低调点的名字吧:arp协议(地址转发协议/地址映射协议)

所以,现在每台主机里就存了一张arp的关系缓存表,记录下了IP对应的MAC地址,这样就能确保信息能发对人了!

来个角色扮演,回顾一下整个传输过程吧~

作为电脑:

  • 首先我要知道我的 IP 以及对方的 IP
  • 通过子网掩码判断我们是否在同一个子网
  • 在同一个子网就通过 arp 获取对方 mac 地址直接扔出去
  • 不在同一个子网就通过 arp 获取默认网关的 mac 地址直接扔出去

作为交换机:

  • 我收到的数据包必须有目标 MAC 地址
  • 通过 MAC 地址表查映射关系
  • 查到了就按照映射关系从我的指定端口发出去
  • 查不到就所有端口都广播发出去,看谁留下了数据,并且还给我反馈,我就补充一下映射关系

作为路由器:

  • 我收到的数据包必须有目标 IP 地址
  • 通过路由表查映射关系
  • 查到了就按照映射关系从我的指定端口发出去(不在任何一个子网范围,走其路由器的默认网关也是查到了)
  • 查不到则返回一个路由不可达的数据包

再来回顾一下,这过程中的记录文件:

  • 交换机中有MAC 地址表用于映射 MAC 地址和它的端口
  • 路由器中有路由表用于映射 IP 地址(段)和它的端口
  • 电脑和路由器中都有arp 缓存表用于缓存 IP 和 MAC 地址的映射关系

最后回顾一下,这些文件是怎么更新的:

  • MAC 地址表:是通过以太网内各节点之间不断通过交换机通信,不断完善起来的
  • 路由表:是各种路由算法 + 人工配置逐步完善起来的
  • arp 缓存表:是不断通过 arp 协议的请求逐步完善起来的

你看了一眼附近的小伙伴!他们好像都听明白了!你决定提高一个难度,挑战一下跨多个路由器的信息传递:

这里只要解决一个问题:路由器之间如何进行连接?

其实这个问题早就在路由表里已经解决了,那就是“下一跳”,来看下路由表:

你看,IP是“192.168.2.0/24”对应的下一跳,是通往路由器2的某一个端口,这样就可以连接多个路由器了!

终于,电脑A可以发消息给电脑F了:

好记性不如烂笔头,还是用文字把整个过程写下来吧:

  1. 电脑A(IP:192.168.0.1)通过子网掩码(255.255.255.0)计算出电脑F(IP:192.168.2.2)跟自己不在同一个子网中, 于是决定把数据包发给默认网关(IP:192.168.0.254)
  2. 电脑A先去查了一下arp缓存表,知道了默认网关192.168.0.254对应设备的MAC地址
  3. 电脑A把数据包加上了如下信息:


  4. 1号交换机收到数据包,根据“目标MAC”,查了一下MAC地址表,发现对应的端口是在3号,于是数据包从3号端口发出去
  5. 数据从3号端口出去,来到了1号路由器,路由器发现“目标IP”是192.168.2.2,查了一下路由表,192.168.2.XXX的IP,需要去下一跳,下一跳的IP是192.168.100.5
  6. 然后又查了一下路由表,发现192.168.100.XXX对应的端口是2号端口
  7. 数据又从1号路由器的2号端口发了出去,就通向了2号路由器
  8. 2号路由器收到了数据包,发现“目标IP”是192.168.2.2,也查了一下自己的路由表,192.168.2.2对应的端口是1号
  9. 顺便,2号路由器查了一下arp缓存表,把192.168.2.2对应的MAC地址找到,并替换了原本的“目标MAC地址”,然后从1号端口发出去
  10. 3号交换机收到了数据包,根据“目标MAC地址”查了一下MAC地址表,发现应该从6号端口发出去
  11. 电脑F收到了数据包,检查了一下“目标MAC地址”,发现就是自己,于是收下了数据包!

终于!你可以和所有的小伙伴一起联机玩耍了~不! 你想多了,你现在还只是能和其他电脑联机,至于数据包的传递细节还没理明白。


-----------------------------------------------这是条华丽的分割线------------------------------------------------


你想着,数据通过互联网传输的时候不可能是光秃秃的不加标识,如果这样数据就会乱。 所以数据在发送的时候,每经过一个环节,需要加上特定标识,加上特定标识的过程叫做数据的封装, 在数据使用的时候再去掉特定标识,去掉特定标识的过程就叫做分用
TCP/IP协议的数据封装和分用过程大致如下图:

为啥要这么做呢?因为网络传输数据包(报文),算是一个很虚拟的过程,这个虚拟的东西经过一个个物理网络层的时候, 需要去满足每一环节的协议,才能被这一层的物理网络所接受。

实际上,咱们也不关心数据是如何在物理机器层面上传递的,因为TCP协议已经帮大家屏蔽了物理层的复杂性。

因此,只需要了解TCP和HTTP就足够了。

大发明家!开始战斗吧!

先来看看你设计的TCP协议的报文格式:


① 源端口号:

源端口号表示报文的发送端口,占16位。源端口和源IP地址组合起来,可以标识报文的发送地址

② 目的端口号:

目的端口号表示报文的接收端口,占16位。目的端口和目的IP地址相结合,可以标识报文的接收地址

有“源端口和IP”加上“目标端口和IP”,从而确定一条TCP连接。嗯~你满意地点点头~

对了!你还希望你的数据包除了能送达到目的地以外,包里的数据顺序千万不能乱,那就给每个字都加上序号吧!

③ 序号(SN):

序号占用4字节,即32位。它的范围是 [0,232−1],也就是说一共有4294967296个序号。

  • 字节的序号:数据包的内容以字节单位进行传输,每一个字节都有一个序号。第一个字节是初始序列号+1

初始序列号,取个名字叫ISN

这个初始序列号从几开始比较好?你想来想去,还是随机好了!这个随机的机制要高大上一点才拿的出手...

挨千刀的你是这么发明的:

  • 当操作系统初始化的时候,有一个全局变量A,这个A可以是1,也可以是0
  • 每隔4毫秒,变量A都要+1
  • 如果加到了最大值(4294967296),那就回到0,又重新来一轮(每一轮也就几个小时的事)
  • 任意时候发送数据包,就取当时的这个变量A的值,当做“初始序列号”,第一个字节就是ISN+1

这个“任意时候”对系统来说,需要有一个控制按钮来告诉它。这个控制按钮,你把它叫做SYN

  • 当SYN = 1时,当前为连接建立阶段,ISN开始取号
  • 当SYN = 0时,取号完毕!可以准备传输数据了,第一个字节ISN+1,第二个字节ISN+2,以此类推...

例如:你发送一个“hello”给女朋友:

  • 你按下【发送】的时候,假设系统获取到全局变量A=2379453244,ISN=2379453244
  • 那么第一个字母“h”的序号=2379453245,之后的每个字母都会在前一个序号上+1。
  • 当数据经过物理层,传输到女朋友那边的网络时,TCP又会检查“有没有重复的序号?”、“序号的顺序是不是对的?”、“有没有丢失序号?” 从而保证你女朋友收到的是“hello”而不是“llohe”

因为数据包很有可能会过大,无法一次性传输完成,那简单,分多个包反复传递就行了。

分多个包传递,就担心出现丢包的情况,一旦丢包数据不就连不上了吗?那就在收包的地方加一个“确认序号”,来保证包的连贯性吧!

④ 确认序号(ACK Number):

“确认序号”待在另一头(也就是服务器)接收数据,收到数据后,会返回一个“期望序号”,这个期望序号就是期望下一次数据发过来时的字节SN序号。

如果,你要发很长很长的一段数据,由于数据量大,于是决定拆成多个包进行传递,假设ISN=0,每个包有1000字节,那么:

  • 客户端发送第一个包,SN从1开始,发1000字节,即SN=1~1000
  • 服务器收到了第一个包,发现最后一个字节的SN是1000,于是ACK Number=1001,希望下一个包的第一个字节序号是1001
  • 客户端收到ACK Number=1001,于是第二个包的SN从1001开始,再发1000字节,即SN=1001~2000
  • 服务器收到了第二个包,发现最后一个字节的SN是2000,于是ACK Number=2001,希望下一个包的第一个字节序号是2001
  • 客户端收到ACK Number=2001,于是第三个包的SN从2001开始,再发1000字节,即SN=2001~3000
  • ... ...
  • 直到所有包都传递完成!

那要怎么防止丢包呢?还是相同的场景,假设第二个包服务器没收到:

  • 客户端发送第一个包,SN从1开始,发1000字节,即SN=1~1000
  • 服务器收到了第一个包,发现最后一个字节的SN是1000,于是ACK Number=1001,希望下一个包的第一个字节序号是1001
  • 客户端收到ACK Number=1001,于是第二个包的SN从1001开始,再发1000字节,即SN=1001~2000
  • 此时网络波动,导致第二个包没收到,那么ACK Number仍然保持在1001,把ACK Number=1001再一次发给客户端
  • 客户端收到ACK Number还是等于1001,于是第三个包的SN依旧从1001开始,把刚刚的包再发一次
  • 此时网络恢复正常。服务器收到了第三个包,发现最后一个字节的SN是2000,于是ACK Number=2001,希望下一个包的第一个字节序号是2001
  • ... ...
  • 直到所有包都传递完成!

其实,不是收到的所有包,都需要生成ACK Number,它也有一个控制按钮,你把它取名为ACK

  • 当ACK = 1时,根据最后一个字节的SN生成ACK Number
  • 当ACK = 0时,不会生成ACK Number

⑤ 头部长度:

作用不大,就是统计一下TCP报文首部的长度。

⑥ 预留6位:

头部长度后面预留的字段长度为6位,作为保留字段,暂时没有什么用处。

⑦ 控制标志:

具体的标志位为:URG、ACK、PSH、RST、SYN、FIN。每个标志有不同的作用:


⑧ 窗口大小:

此字段用来进行流量控制。流量控制的单位为字节数,这个值是本端期望一次接收的字节数(注意是“期望字节数”,不是“最大字节数”)

⑨ 校验和:

由发送端计算出“校验和”(具体怎么计算的不关心),接收方收到数据包后,会来比对校验和,如果一致,则接收包;如果不一致,这个包将会被丢弃。

⑩ 紧急指针:

需要配合URG标志位一起使用。当URG=1时,紧急指针指向的那个字节SN,才会被紧急占位。换句话说,就是“我放了一个紧急数据在数据流中,接收方你看着办吧”


以上十项内容是TCP报文首部必须的字段,也称固有字段,长度为20个字节。接下来是TCP报文的可选项和填充部分:

⑪ 可选项和填充部分:

最常见的选项字段是MSS(最长报文大小)。表示当前连接方所能接受的最大报文段的长度。

一口气讲了这么多,最后来总结一下TCP报文为什么是一个可靠的协议:

  • 应用数据分割成TCP认为最适合发送的数据块。这部分是通过MSS(最大数据包长度)选项来控制的,通常这种机制也被称为一种协商机制, MSS规定了TCP传往另一端的最大数据块的长度。一般来讲,MSS值还是越大越好,这样可以提高网络的利用率
  • 有重传机制。设置定时器,等待确认包,如果定时器超时还没有收到确认包,则报文重传
  • 对首部和数据进行校验
  • 接收端会对收到的数据进行根据序号排序,然后再交给应用层
  • 接收端发现重复序号,丢弃重复的数据
  • TCP还会提供流量控制

TCP真是个好东西!


-----------------------------------------------喝口水歇会------------------------------------------------


还有一个东西不得不扫个盲,也就是人们常说的:三次握手和四次挥手

三次握手


  • 第一次握手:
    • 客户端进入SYN_SENT(已发送)状态。
    • 发送一个SYN标志位=1,表示“我想开一个连接通道”
    • 同时会带上客户端分配好的SN序列号、MSS(最大报文段长度)可选项的值
  • 第二次握手:
    • 服务端在收到SYN帧之后,会进入SYN_RCVD(已接收)状态
    • 服务端返回SYN+ACK帧给客户端,表示“我已收到请求连接的消息,现在跟你确认一些信息”
  • 第三次握手:
    • 客户端在收到SYN+ACK确认帧后,为表诚意,将自己的状态变成ESTABLISHED(连接已建立)。
      表示“确认无误,客户端接通道已建立成功”。
    • 同时,客户端发ACK帧给服务端。服务端收到ACK帧后,也会进入ESTABLISHED(连接已建立)状态。
      表示“服务器连接通道已经建立成功”

三次握手后,数据开始各种传输。等数据传输完成后,连接将断开,断开的过程需要经历四次挥手...

四次挥手


双方都可以主动提出分手,无论是谁提出的,都要挥手四次才能断干净

  • 第一次挥手:
    • 主动断开方 向对方发送一个FIN结束请求报文,FIN=1(表示要分手),并把SN序列号和ACK Number确认号准备好
    • 主动断开方 进入FIN_WAIT_1(等待终止中_1)状态,表示“我已无数据要给你了,请求断开”
  • 第二次挥手:
    • 被动断开方 收到FIN=1,会发送一个ACK响应报文,响应报文中有一个ACK Number确认号=SN+1
    • 被动断开方 就进入了CLOSE-WAIT(关闭等待)状态,表示“我同意你的连接断开请求,但是我还得再缓缓”
    • 被动断开方 在本地检查是否有剩余数据要传给主动断开方,再设置了一个CLOSE-WAIT状态持续的时间
    • 主动断开方 收到ACK报文后,由FIN_WAIT_1(等待终止中_1)转换成FIN_WAIT_2(等待终止中_2)状态
  • 第三次挥手:
    • 被动断开方 将剩余数据发给主动断开方,如果没有数据要传,就等CLOSE-WAIT状态持续的时间截止。
    • 被动断开方 会向主动断开方发送一个FIN+ACK结束响应报文,表示“我也没数据要给你了,你想好是不是真的要断”
    • 被动断开方进入LAST_ACK(最终确认)状态
  • 第四次挥手:
    • 主动断开方 收在到FIN+ACK断开响应报文后,向被动断开方发送一个ACK确认报文,表示“我确认要断!”
      自己进入TIME_WAIT(等待时间)状态
    • 被动断开方 在收到主动断开方的最后的ACK报文以后,知道对方真的要断。无奈,最终关闭了连接,也不再理会对方了
    • 主动断开方 等待完成2MSL的时间后,如果期间没有收到其他报文,表示“对方已经关闭,我已可以关闭了”,连接最终关闭。
    2MSL:一次消息的来回(一个发送和一个回复)所需的最大时间。一般维持在1-4分钟之间

通过三次握手建立连接和四次挥手拆除连接,一次TCP的连接建立及拆除,至少进行7次通信,可见其成本是很高的。

5. 什么是接口

在两个不同的系统或者一个系统中两个不同功能,他们之间相互连接的部分称为接口。 是指系统或组件之间的交互点,通过这些交互点可以实现数据的交互。(数据交互的通道)


6. 接口的类型:按照范围划分

  • 系统之间的接口:多个内部系统之间的交互,内部系统与外部系统之间的交互
  • 程序内部的接口:方法与方法之间,模块与模块之间的交互

接口测试,一般情况下做的是“系统之间的接口”

7. 接口的类型:按照所遵循协议的不同

  • HTTP接口,它是基于超文本传输协议(HyperText Transfer Protocol,HTTP)开发的接口,但不能排除没有使用其他协议。
  • Web Server接口,它是系统对外的接口,比如你要从别的网站或服务上获取资源,一般来说,别人不会把数据库共享给你, 他们会提供一个他们写好的方法,让你用来获取数据,你使用他们写好的方法就能引用他们提供的接口,从而达到同步数据的目的
  • RESTful接口。简称为REST,其描述了一个架构样式的网络系统,核心是面向资源。REST专门针对网络应用设计和开发方式, 降低开发的复杂性,提高系统的可伸缩性。
接口测试,一般情况下做的是“HTTP接口”,RESTful接口近年也很普遍

总而言之,我们要做的接口测试,一般是【前端系统】与【后端系统】之间,基于HTTP协议的接口。作用是进行数据传输

题外话:前后端分离是近年来Web应用开发的一个发展趋势。这种模式具有以下优势

  • 后端工程师不用精通前端技术(如HTML、JavaScript或CSS),只专注于数据处理,对外提供API即可。
  • 前端工程师的专业越来越强,其通过API获取数据,并专注于页面设计。
  • 前后端分离可扩大接口的应用范围,开发的接口可以应用到Web页面上,也可以应用到APP上。
正是因为前后端分离模式高度依赖于API的准确性,接口测试的地位也逐步上升。

8. HTTP协议

概念:HTTP(HyperText Transfer Protocol)超文本传输协议,是一个基于请求与响应模式的、应用层的协议, 也是互联网上应用最为广泛的一种网络协议。

广泛到什么程度呢?广泛到所有的万维网文件都必须遵守这个标准

Q:什么是“万维网”?

答:WWW (World Wide Web,万维网):是存储在Internet计算机中、数量巨大的文档的集合。这些文档称为页面

Q:什么是“页面”?

答:它是一种超文本(Hypertext)信息,可以用于描述超媒体

Q:什么是“超媒体”?

文本、图形、视频、音频等多媒体,称为超媒体(Hypermedia)。

Q:是什么使得超媒体能联合起来,变成万维网上的网页?

答:超链接(Hyperlink)

Q:超链接传输文件时,需要遵守什么协议?

HTTP(HyperText Transfer Protocol)超文本传输协议

Q:超链接是怎么知道要从服务器里,取哪些文件进行传输?

答:URL(Uniform Resource Locator)统一资源定位符


破案:超媒体存在服务器上 ---> 超链接(遵守HTTP协议)通过URL拿到服务器资源 ---> web浏览器读取渲染(html文件、JS脚本等) ---> 一个美观的网页 ---> 网站

换个思路:

服务器数据库存了数据
-->后端代码根据需求整合了数据
--->封装成接口,并给接口认领了个URL
--->超链接通过URL拿到接口资源
---> 前端语言解析接口里的数据,把数据合并前端HTML文件中
--->web浏览器读取渲染
--->形成一个美观又有数据的网页
--->能解决用户需求的网站


由此看来,第一个要了解的是HTTP的“URL”

9. URL相关知识

URL概念:

统一资源定位符,是互联网上标准资源的地址。HTTP使用URL来建立连接和传输数据。

URL格式:

http://www.litemall360.com:8080/admin/goods/list?page=1&limit=20&sort=add_time&order=desc


  • 协议部分:【http】,常见的协议有HTTP,HTTPS、FTP等
  • 域名部分:【www.litemall360.com】,也可以使用IP地址作为域名使用
  • 端口部分:【8080】,端口可以省略,默认端口(HTTP:80,HTTPS:443,FTP:21)
  • 资源路径部分:【/admin/goods/list】,该资源在项目里的位置
  • 携带参数部分:【page=1&limit=20&sort=add_time&order=desc】,可以允许有多个参数,多个之间用“&”作为分隔符

URL是HTTP请求部分的内容,接下来看看HTTP完整的请求部分↓↓↓

10. HTTP请求的组成

http请求由三部分组成,分别是:请求行、请求头、请求体

  • 请求行:
    • 请求方式
    • URL
    • 协议版本
  • 请求头:
    • 键值对组成,每行一对。描述客户端的基本信息,把客户端相关信息告知服务器
  • 请求体:
    • 用来存放通过POST、PUT方式提交到服务器的数据

① 常用请求方式:

  • GET:从服务器获取资源
  • POST:在服务器新建一个资源
  • PUT:在服务器更新资源
  • DELETE:从服务器删除资源

② 不常用请求方式:

  • HEAD:请求获取由Request-URI所标识的资源的响应消息报头
  • TRACE:请求服务器回送收到的请求信息,主要用于测试或诊断
  • CONNECT:保留将来使用
  • OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项和需求

③ 常用的请求头

  • User-Agent:产生请求的浏览器类型
  • Accept:客户端可识别的内容类型列表
  • Content-Type:请求体数据的类型
  • Content-Length:请求体的大小
  • Token:该值为开发自定义,开发可以随意更改名称。用于反馈用户身份令牌

④ 请求头中的“Content-Type”:

很重要!很重要!很重要!

直接规定了请求体数据的类型,数据传递需要满足指定的类型

  • text/html:HTML格式
  • text/plain:纯文本格式
  • image/jpeg:jpg图片格式
  • application/json:JSON数据格式
  • application/x-www-form-urlencoded:form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据格式)
  • multipart/form-data:在表单中进行文件上传时使用

⑤ 请求体的内容

  • 请求体不在GET方法中使用,经常在POST、PUT方法中使用
  • 请求体的数据可以是:表单数据、文本、XML、JSON。由请求头中的“Content-Type”来决定

HTTP除了请求部分,还有一个非常重要的部分,就是“响应部分”↓↓↓

11. HTTP响应的组成

HTTP响应也由三个部分组成,分别是:状态行、响应头、响应体

  • 状态行
    • 协议版本号
    • 状态码
    • 状态消息
  • 响应头
    • 用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理响应数据
    • Set Cookies:设置客户端本地cookies缓存
  • 响应体
    • 响应的消息体,数据可以是普通文本、XML、JSON、HTML源码

① 状态码分类

状态码有三位数字组成,第一个数字定义了响应的类别

  • 1xx:指示信息--表示请求已接收,继续处理
  • 2xx:成功--表示请求已被成功接收、理解、接受
  • 3xx:重定向--要完成请求必须进行更进一步的操作
  • 4xx:客户端错误--请求有语法错误或请求无法实现
  • 5xx:服务器端错误--服务器未能实现合法的请求

② 状态码详解:

1xx:这一组状态码表明这是一个临时性响应。此响应仅由状态行和可选的HTTP头组成,以一个空行结尾。


2xx:这一组状态码表明客户端的请求已经被服务器端成功接收并正确解析。

常用:200、201、202、204


3xx:这一组状态码表示客户端需要采取更进一步的行动来完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。

常用:301、302


4xx:这一组状态码表示客户端的请求存在错误,导致服务器无法处理。

常用:400、401、403、404、406


5xx:这一组状态码说明服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。

常用:500、503


了解了HTTP的请求部分和响应部分,再来看看后端程序员编写的接口文档长什么样子↓↓↓

12. 接口文档知识点

① 什么是接口文档

又称为API文档,一般是由开发人员所编写的,用来描述系统所提供接口信息的文档。程序员们根据这个接口文档的要求进行开发,并需要一直维护和遵守

② 为什么要写接口文档

  • 能够让前端开发与后台开发人员更好的配合,提高工作效率。(有一个统一参考的文件)
  • 项目迭代或者项目人员更迭时,方便后期人员查看和维护
  • 方便测试人员进行接口测试

③ 接口文档的内容

一个规范的接口文档,要包含以下信息:

  • 基本信息
    • 接口名称
    • 请求方法
    • 请求路径
    • 接口描述
  • 请求参数
    • 请求头
    • 请求体(包含具体的请求参数名称、参数类型、是否必须、示例、备注)
  • 返回数据
    • 不同情况的响应状态码
    • 响应数据(包含具体的响应数据名称、类型、是否必须、默认值、示例、备注)

案例:


最后,来看看现在主流的接口风格↓↓↓

思考:

如何让前端开发与后台接口开发人员更好的配合,提高工作效率?

无规矩不成方圆,制定接口规范


① 传统接口风格

例如:如下是对用户进行操作的相关接口,包括增删改查


特点:

  • 基本上都是使用的GET和POST请求方式
  • 每一个功能对应一个接口URL,每个接口都相对独立,互不相干

② RESTful接口风格

REST:即(Representational State Transfer)的缩写。词组的翻译是"表现层状态转化" 。如果一个架构符合REST原 则,就称它为RESTful架构。

例如:如下还是对用户进行操作的相关接口,包括增删改查


特点:

  • 每一个URL代表一种资源
  • 客户端和服务器之间,传递这种资源的某种表现层
  • 客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"
  • 接口之间传递的数据最常用格式为JSON

常用的HTTP动词有下面四个

  • GET:从服务器获取资源 ( 一项或多项)
  • POST:在服务器新建一个资源
  • PUT:在服务器更新资源
  • DELETE:从服务器删除资源