TCP/IP 通信传输流

1,764 阅读15分钟

TCP/IP 五层协议

在讲解 TCP/IP 通信传输流之前,首先复习一下 TCP/IP 的五层协议。

应用层:决定向用户提供应用服务时通信的活动。TCP/IP 协议族内预存了各类通用的应用服务。比如:FTP、DNS、HTTP 协议。

传输层:传输层对上层应用层,提供处于网络连接中的两台计算机之间的数据传输。在传输层有两个性质不同的协议,分别是 TCP (Transmission Control Protocol,传输控制协议) 和 UDP (User Data Protocol,用户数据报协议)

网络层:网络层用来处理在网络上流动的数据包。数据包是网络传输的最小数据单位。该层规定了通过怎样的路径到达对方计算机,并把数据包传送给对方。与对方计算机通过多台计算机或网络设备进行传输时,网络层所起的作用就是在众多的选项内选择一条传输路线。

数据链路层: 在物理层提供比特流服务的基础上,建立相邻结点之间的数据链路,通过差错控制提供数据帧 (Frame)在信道上无差错的传输,并进行各电路上的动作系列。数据的单位称为帧 (frame)

物理层:物理层建立在物理通信介质的基础上,作为系统和通信介质的接口,用来实现数据链路实体间透明的比特 (bit) 流传输。只有该层为真实物理通信,其它各层为虚拟通信。

TCP/IP 数据传输流程

客户端在应用层 (HTTP 协议) 发出一个 HTTP 请求。

为了方便传输,在传输层 (TCP 协议) 把从应用层处收到的数据 (HTTP 请求报文) 进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。

在网络层 (IP 协议),增加作为通信目的地的 MAC 地址后转发给数据链路层。这样,发送给服务端的请求就准备齐全了。

当服务端在链路层接收到数据时,按序往上层发送,一直到应用层。当传输到应用层时,才算真正的接收到由客户端发送过来的请求。

什么是 MAC 地址?

媒体访问控制地址 (Media Access Control Address),也称为局域网地址 (LAN Address),以太网地址 (Ethernet Address) 或物理地址 (Physical Address),它是一个用来确认网上设备位置的地址。ARP (Address Resolution Protocol) 是一种用来解析地址的协议,它可以根据 IP 地址反查出对应的 MAC 地址。

下图展示了一台电脑内网 IP 和 MAC 地址。在终端 (MAC OS 环境) 输入 ifconfig,找到 en0,便可查找本地以太网的信息。

那么什么是 MAC 地址呢?我们知道 IP 地址是可变的,可以通过各种方式分配 IP 地址给一个设备,比如 DHCP, PPP,静态 IP 等。而 MAC 地址一般来讲是不会变的,设备在生产时就被“烙”上了 唯一的标识,这个 唯一的标识 就是 MAC 地址。

逼乎上有个很有趣的例子:你中午在公司点了份外卖,收货地址一定是写公司的地址;晚上回到家,再点外卖时就得把地址写成家 (IP 是动态的)。但无论在哪儿点外卖,订单上的姓名和手机号一定是你自己的 (MAC 地址)。

中午外卖小哥把午餐送到公司门口,但收外卖的人肯定不止你一个 (多台设备在同一个 broadcast 网络里),因此他会通过手机号和姓名来找到你。

UDP 协议

用户数据报协议 (User Datagram Protocol),又称使用者资料包协议,是一个简单的面向数据报的传输协议。在 TCP/IP 模型中,UDP 为网络层以上和应用层以下提供了一个简单的接口。UDP 只提供数据的 不可靠传递,它一旦把应用程序发给网络层的数据发送出去,就不保留数据备份。UDP 在 IP 数据报的头部仅仅加入了复用和数据校验 (字段)。

它的特点如下

  • UDP 缺乏可靠性。UDP 本身不提供确认序号,序列号,超时重传等机制。UDP 数据报可能在网络中被复制,被重新排序。即 UDP 不保证数据报会到达其最终目的地,也不保证各个数据报的先后顺序,也不保证每个数据报只到达一次。

  • UDP 头部开销小,它包含以下几个数据:

      两个十六位的端口号,分别是源端口和目的端口。
      
      整个数据报文的长度。
      
      整个数据报文的校验和,用于发现头部信息和数据中的错误
    
  • UDP 是面向无连接的。UDP 客户端和服务器之前不必存在长期的关系。UDP 发送数据报之前也不需要经过握手创建连接的过程。

  • UDP 不仅支持单播,还支持多播和广播。

基于 UDP 协议的有:

域名系统 (DNS)

    DNS在进行区域传输的时候使用TCP协议,其它时候则使用UDP协议;

简单网络管理协议 (SNMP)

动态主机配置协议 (DHCP)

路由信息协议 (RIP)

TCP 协议

TCP (Transmission Control Protocol, 传输控制协议) 是一种面向连接的、可靠的、基于字节流服务的传输层通信协议,由 IETF 的 RFC 793 定义。其中字节流服务 (Byte Stream Service) 是指为了方便传输,将大块数据分割成以报文段 (segment) 为单位的数据包进行管理。

  • TCP 提供一种面向连接的、可靠的字节流服务

  • 在一个 TCP 连接中,仅有两方进行彼此通信。广播和多播不能用于 TCP

  • TCP 使用校验和,确认和重传机制来保证可靠传输

  • TCP 给数据分节进行排序,并使用累积确认保证数据的顺序不变和非重复

  • TCP 使用滑动窗口机制来实现流量控制,通过动态改变窗口的大小进行拥塞控制

TCP 报文

端口号:包括源端口号和目的端口号,用来标识同一台计算机的不同的应用进程。TCP 报头中的源端口号和目的端口号同 IP 数据报中的源 IP 与目的 IP 唯一确定一条 TCP 连接。

源端口号:源端口和 IP 地址的作用是标识报文的返回地址。

目的端口号:目的端口指明接收方计算机上的应用程序接口。

序号:它是当前报文段发送的数据组的第一个字节的序号。在 TCP 传送的流中,每一个字节一个序号。比如一个报文段的序号为 300,此报文段的数据部分共有 100 字节,则下一个报文段的序号为 400。序号 确保了 TCP 传输的有序性。

**确认号:**即 ACK(acknowledgement),指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当 ACK 标志为 1 时才有效。比如建立连接时,SYN 报文的 ACK 标志位为 0。

首部长度:由于首部可能含有可选项内容,因此 TCP 报头的长度是不确定的,报头不包含任何任选字段则长度为 20 字节,4 位首部长度字段所能表示的最大值为 1111,转化为 10 进制为 15,15*32/8 = 60,故报头最大长度为 60 字节。首部长度也叫数据偏移,是因为首部长度实际上指示了数据区在报文段中的起始偏移值。

保留:为将来定义新的用途保留,现在一般置 0。

窗口:滑动窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小是一个 16bit 字段,因此窗口大小最大为 65535。

校验和:奇偶校验,此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。

紧急指针:只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。

选项和填充:最常见的可选字段是最长报文大小,又称为 MSS (Maximum Segment Size),每个连接方通常都在通信的第一个报文段 (为建立连接而设置 SYN 标志为 1 的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是 32 位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证 TCP 头是 32 的整数倍。

数据部分:TCP 报文段中的数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中,也会发送不带任何数据的报文段。

上面写了那么多是不是不太好记,其实不用全都记住,记住个大概流程

TCP 建立连接 (三次握手)

所谓三次握手 (three-way handshaking) 是指建立一个 TCP 连接时,需要客户端和服务端共发送三个包。它的目的是连接服务器指定端口,建立 TCP 连接,并同步双方的 序列号 和 确认号,交换 TCP 窗口大小信息。在 socket 编程中,当客户端执行 connect() 函数时,将触发三次握手。

SYN:同步序列编号(Synchronize Sequence Numbers)。是TCP/IP建立连接时使用的握手信号。在客户机和服务器之间建立正常的TCP网络连接时,客户机首先发出一个SYN消息,服务器使用SYN+ACK应答表示接收到了这个消息,最后客户机再以ACK消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递。

seq:序列号,什么意思呢?当发送一个数据时,数据是被拆成多个数据包来发送,序列号就是对每个数据包进行编号,这样接受方才能对数据包进行再次拼接。

ack:这个代表下一个数据包的编号,这也就是为什么第二请求时,ack是seq+1,

第一次握手

客户端首先发送一个 SYN 为 1 的包给服务端,指明客户端要连接服务端的哪个接口以及初始序号 x。发送完毕后,客户端进入 SYN_SEND 状态。

第二次握手

服务端收到后,回传一个带有 SYN/ACK 的确认包以示应答。即 SYN=1,ACK=1。服务端选择自己的 ISN 序列号,放到 seq 中,同时将确认序号 ack 设置为客户端的 ISN+1,即 x+1。发送完毕后,服务端进入 SYN_RCVD (同步收到) 状态。

第三次握手

客户端收到确认后,再次发送一个带 ACK 标志的数据包。即 ACK=1,ack=y+1,并将自己的序列号 seq=x+1。发送完毕后,客户端和服务器双双进入 ESTABLISHED 状态。至此,三次握手结束。

为什么是三次握手,两次不行吗?

为了实现可靠数据传输,TCP 协议的通信双方,都必须维护一个序列号,以标识发送出去的数据包中,哪些是已经被对方收到的。三次握手的过程即是通信双方相互告知序列号起始值,并确认对方已经收到了序列号起始值的必经步骤

如果只是两次握手,至多只有连接发起方的起始序列号能被确认,另一方选择的序列号则得不到确认。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP 还设有一个保活计时器 (keep-alive),如果客户端出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为 2 小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔 75 秒发送一次。若一连发送 10 个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

TCP 关闭连接 (四次挥手)

第一次挥手

客户端调用 close() 函数,并发送一个 FIN (finish) 标志为 1 的数据包给服务端,来表示本方的数据已经全部发送完毕,此时客户端进入 FIN_WAIT_1 状态。TCP 规定,FIN 报文段即使不携带数据,也要消耗一个序号。

第二次挥手

服务端收到客户端的释放报文后,发出确认报文,其中 ACK=1, ack=u+1,并且带上自己的序列号 seq=v。表明自己接受到了客户端关闭连接的请求,但还没准备好关闭连接 (半关闭状态),也就是说客户端已经没有数据要发送了,但服务端仍有可能会发送数据。发送完毕后,服务端进入 CLOSE_WAIT 状态。

当客户端收到该报文后,客户端就进入 FIN-WAIT-2 状态,等待服务器发送连接释放报文。

第三次挥手

服务器端准备好关闭连接时,会向客户端发送一个连接释放报文,其中 FIN=1,ack=u+1。由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为 seq=w。发送完毕后,服务端便进入 LAST-ACK(最后确认) 状态。

第四次挥手

客户端收到服务器的连接释放报文后,需要发送一个确认包,其中 ACK=1,ack=w+1,而自己的序列号是 seq=u+1,并进入了 TIME-WAIT (时间等待)状态,等待过程可能出现的要求重传的 ACK 包。

此时 TCP 连接还没有释放,必须经过 2 * MSL (Maximum Segment Lifetime, 最长报文段寿命) 时间后,当客户端撤销相应的 TCB 后,才会进入 CLOSED 状态。

而服务器只要收到了客户端发出的确认,立即进入 CLOSED 状态。同样,撤销 TCB 后,就结束了这次的 TCP 连接。因此,服务器结束 TCP 连接的时间要比客户端早一些。

TCP 有哪些手段保证可靠交付

udp和tcp的区别

dns

DNS 报文格式

请求报文和 DNS 服务器返回的应答报文都是统一的格式:

会话标识 (2 字节):它是 DNS 报文的 ID 标识,对于请求报文和其对应的应答报文,这个字段是相同的,通过它可以区分 DNS 应答报文是哪个请求的响应。

标志 (2 字节):它有 8 个部分,如下图所示:

Questions 查询字段

QNAME 无符号 8bit 为单位长度不限表示查询名。

QTYPE 无符号 16bit 整数表示查询的协议类型。

QCLASS 无符号 16bit 整数表示查询的类。

Answer/Authority/Additional

三者的格式相同,如下所示:

DNS 解析记录

折腾过搭建网站的小伙伴们一定对 DNS 解析记录不会陌生,下面通过表格复习一下。

域名解析过程

  • 系统会检查浏览器缓存中有没有这个域名对应的解析过的 IP 地址,如果缓存中有,这个解析过程就将结束。浏览器缓存是受这个域名的失效时间和缓存的空间大小控制的。

  • 如果用户的浏览器缓存中没有,浏览器会查找操作系统缓存中即为本地的 Host 文件。

  • 路由器也可能会有缓存。

  • 如果前几步都没有找到,就会到 LDNS (Local DNS) 中查找,LDNS 是你的 ISP 分配给你的 DNS (一般为两个),大部分情况下域名都会在这里得到解析。下图是 cloudflare 提供给我的两个 DNS。

  • 如果在 LDNS 没有找到,那就要去 Root Server 域名服务器请求解析了。根域名服务器返回给本地域名服务器一个 查询主域名服务器(gTLD Server)地址。gTLD 是国际顶级域名服务器,如.com,.cn、.org 等,全球只有 13 台左右。
  • 本地域名服务器会向 gTLD Server 地址发送请求,它会返回一个 Name Server 域名服务器的地址,这个 Name Server 通常就是你注册域名的厂家,比如 NameCheap、狗爹、万网等等。
  • Name Server 域名服务器会查询存储域名和 IP 的关系映射表,正常情况下都可以根据域名得到目标 IP 记录,并连同一个 TTL 返回给本地域名服务器。
  • 本地域名服务器根据 TTL 缓存这个 IP,并将解析结果返回给客户端,客户端再根据 TTL 将 IP 信息缓存到本地系统缓存里。至此,域名解析过程结束。