传输层协议:TCP和UDP

诗人和酒 · · 152 次点击 · · 开始浏览    

传输层:TCP和UDP

使用IPv4和IPv6的应用程序

平时我们使用的tcpdumppingtraceroute属于TCP/IP协议族,虽然叫TCP/IP协议族,但是这个协议族还涉及到许多其他成员。下图是其概貌。

在这里插入图片描述

  1. tcpdump直接同数据链路层通信,使用BPF或DLPI的接口不用套接口或XTI。
  2. tcpdump以外的9个应用程序通常是套接口或XTI。
  3. traceroute程序使用两种套接口:IP接口和ICMP套接口。
  4. ICMP,网际控制消息协议。处理路由器和主机之间的错误和控制消息,ping程序使用ICMP。

ping和ICMP
下图是ping百度主页的结果:

Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
64 bytes from 14.215.177.39: icmp_seq=0 ttl=55 time=4262.004 ms
64 bytes from 14.215.177.39: icmp_seq=1 ttl=55 time=3726.616 ms
64 bytes from 14.215.177.39: icmp_seq=2 ttl=55 time=4887.194 ms
64 bytes from 14.215.177.39: icmp_seq=3 ttl=55 time=4479.124 ms
Request timeout for icmp_seq 8
64 bytes from 14.215.177.39: icmp_seq=4 ttl=55 time=5194.957 ms

ICMP没有端口

ping一个端口,是不妥的。如果有人说ping一下80端口通不通,其实指的是发送一个TCP请求探测一下80端口能不能回包。

真正的ping使用的是ICMP,没有端口一说。

无连接、不可靠的UDP

无连接

UDP客户与服务器之间不必存在长期的关系。

一个UDP客户可以通过同一个UDP套接口发送数据报给不同的服务器。
一个UDP服务器可以通过同一个UDP套接口从不同的客户收数据报

不可靠

UDP本身不提供确认、序列号RTT估算、超时及重传机制。

如果一个UDP数据报在网上被复制,那所有的拷贝都可能送到接收方的主机。
如果一个UDP客户发送不同的数据报到同一个目的地,它们的顺序可能被打乱。

在这里插入图片描述

使用UDP的服务

实时音视频聊天、一些在线游戏等时间敏感的应用,适用于UDP。这些场景下,使用者可以忍受一定程度的数据丢包,但是不能容忍过多的延迟。

面向连接、可靠的TCP

面向连接

正如第一章的时间日期程序——“接受客户连接,发送应答”步骤所说:

TCP连接使用三路握手(three-way handshake)来建立,当握手完毕时,accept函数返回,其返回值是一个称为已连接(connected descriptor)的新描述字(connfd)。此描述字用于与新客户的通信。accept为每个连接到服务器的客户返回一个新的已连接描述字。

TCP连接使用三路握手(three-way handshake)来建立,当握手完毕时,accept函数返回,其返回值是一个称为已连接(connected descriptor)的新描述字(connfd)。此描述字用于与新客户的通信。accept为每个连接到服务器的客户返回一个新的已连接描述字。

确认

TCP发送数据,有超时及重传机制,数次重传失败后,TCP才放弃。这一点使得TCP比UDP可能消耗更多的时间。

序号

TCP根据数据分节的序列号,进行排序,去重,将完整的数据传递给应用进程。

流量控制

TCP有接收缓冲区,缓冲区满后,必须等到应用进程从缓冲区读取数据后才能继续接收新的数据。

UDP发送数据不管接收方的缓冲区是不是能装下。

全双工

最后,TCP的连接是全双工的,意味着接收方也可以在下一时刻成为发送方,这一前提下,追踪每个方向上数据流的状态信息(序列号、通告窗口)大小,就显得尤为重要了。

TCP连接的建立和终止

建立:三路握手

建立一个TCP连接的步骤:

  1. 被动打开 服务器通过调用socketbindlisten,准备好接受外来的连接。
  2. 主动打开 客户端调用connect,发送一个SYN分节,告知服务器建立连接后数据的初始序列号。
  3. 服务器确认 服务器必须确认客户端发来的SYN分节,ACK=SYN+1,并且自己也发一个SYN分节给客户端。
  4. 客户端确认 客户端必须确认服务器的SYN。
在这里插入图片描述

TCP选项

下面是第一个分节的抓包,包含了一些选项

16:25:52.755769 IP localhost.60933 > localhost.daytime: Flags [S], seq 1267114631, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 4110257572 ecr 0,sackOK,eol], length 0
    0x0000:  4500 0040 0000 4000 4006 0000 7f00 0001  E..@..@.@.......
    0x0010:  7f00 0001 ee05 000d 4b86 a287 0000 0000  ........K.......
    0x0020:  b002 ffff fe34 0000 0204 3fd8 0103 0305  .....4....?.....
    0x0030:  0101 080a f4fd 8da4 0000 0000 0402 0000  ................
  • MSS选项。TCP发送的SYN中带上这个选项,通知对方它的最大分节大小,即它能接受的每个TCP分节中的最大数据量。
  • 窗口规模选项。TCP双方能够通知对方的最大窗口大小是65535,因为TCP Header里,这个字段只占16位(2^16-1)。
  • 时间戳选项。在高速连接中,一些由于暂时的路由的原因造成的迷途分组,在路由稳定后,正常到达目的地,TS选项可以防止上述过程可能造成的数据损坏。

终止:四次挥手

终止一个TCP连接的步骤:

  1. 主动关闭 某个应用进程首先调用close,我们称这一端执行主动关闭,它发出第一个FIN分节。
  2. 被动关闭
    接收到FIN的端执行被动关闭,确认对这个FIN的接收,这次接收意味着应用进程在相应连接上再也接收不到额外数据(它的接收会作为文件结束符发给被动方应用进程)。
  3. 被动方发起关闭 一段时间后,收到文件结束符的应用进程也调用close关闭它的套接口,向主动方发送一个FIN。
  4. 主动方确认 接收到FIN分节后,主动关闭的一方也要确认这个分节。
在这里插入图片描述

上图演示了客户端发起的主动关闭,实际上无论是客户端还是服务器都可以执行主动关闭。譬如HTTP(超文本传送协议)就是服务器执行主动关闭。

TCP状态转换图

  • 为每一个连接定义11种状态。
  • TCP规则决定状态的转换条件,这种转换基于当前状态及在该状态下所接收的分节。例如: 应用进程在CLOSED状态下执行一个主动打开:
    在这里插入图片描述

SYN_SENT情况下收到附带ACK的SYN:

在这里插入图片描述

应用进程调用close主动关闭:
在这里插入图片描述

应用进程在ESTABLISHED状态下接收到FIN:
在这里插入图片描述

在这里插入图片描述

数据捎带

在TCP的建立连接的三次握手和终止连接的四次挥手之间,是数据分节的传输。此时服务器对客户请求的确认是伴随着服务器的应答发送的。这称为捎带,通常在服务器处理请求并产生应答的时间少于200ms时发生。如果服务器耗用更长的时间,如1s,就会先确认,再应答。

TCP数据传输

在这里插入图片描述

TCP还是UDP

上图这样的单一分节的请求和接收,使用TCP时,包括连接建立和连接终止的7个分节,以及最后一次客户对服务器数据的应答,有8个分节额外需要消耗。如果使用UDP,只有2个分组需要交换。

许多应用程序还是在使用UDP,因为它们需交换的数据量很小,也避免TCP连接建立和终止连接的额外开销。

TIME_WAIT状态

执行主动关闭的那端会在转换成CLOSED之前进入这个状态。

  1. 停留在该状态的持续时间是最长分节生命期MSL的两倍,俗称2MSL
  2. MSL的值选择在30s~ 2min之间,这意味着TIME_WAIT状态的延迟在1min~4min之间。
  3. MSL是IP数据报能在互联网中生存的最长时间。

存在TIME_WAIT状态的两个理由

  1. 实现终止TCP全双工连接的可靠性
    假设最后一个主动关闭方发给被动方的ACK丢失,被动方就会重发最终的FIN,因此主动一方必须维护状态信息,以允许它重发对应的ACK。为了实现全双工关闭(两个方向数据流都彻底关闭),TCP必须正确处理这四个分节中任何一个分节的丢失情况。
  2. 允许老的重复分节在网络中消逝
    由于一个分节最多存在MSL,那么TIME_WAIT等待2个MSL之后,便可以保证老的重复分节已经在网络中彻底丢弃。这样下一次在相同的IP地址和端口建立的连接,必然不会接收到老的请求分节了。

TCP并发服务器
并发服务器中,主服务器通过循环派生子进程来处理每个新的连接。

在这里插入图片描述

整理了一些最新LinuxC/C++服务器开发/架构师面试题、学习资料、教学视频(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享有需要的可以自行添加 学习交流群


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:诗人和酒

查看原文:传输层协议:TCP和UDP

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077

152 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传