TCP&UDP初步

基本概念

TCP:传输控制协议(Transmission Control Protocol

UDP:用户数据报协议(User Datagram Protocol

TCPUDP的一些基本区别:

  1. TCP面向连接,UDP不面向连接。
  2. TCP面向字节,不存在消息边界,所以可能存在粘包问题。UDP则面向报文。
  3. TCP会尽力保证数据的可靠交付,而UDP默认不做保证。
  4. TCP头部20字节,UDP头部8字节。

编者注:如何理解1和3:

TCP协议是一种可靠的通信协议,它要求传输的过程是可靠的,因此需要经过三次握手的环节,确立连接关系之后,才可以进行传输。除此之外,TCP还有超时重传机制,还有排序的机制,有发送的窗口,有窗口大小等等,保证接收方接收到的就是发送方发送过去的。

UDP是一种不可靠的通信协议,它不需要建立连接,不需要对连接进行确认ACK的操作,不需要重传,不需要排序,它只管传输

比如:

“我给你讲一个关于TCP的笑话。”

“好的你给我讲一个关于TCP的笑话。”

“好的。”

------确立连接关系,进行传输------

“苟。这是第一个字。”

“第一个字收到,请发第二个字。”

“利。这是第二个字。”

“第二个字收到,请发第三个字。”

“国。这是第三个字。”

------超时重传-------

“国。这是第三个字。”

“第三个字收到,请发第四个字。”

“家……”

……

“我讲完了。”

“好的。我听完了。”

“好的。”

------关闭连接------

“我给你讲一个关于UDP的笑话。”

“咦我好像听见一个关笑P话的U……?咦这苟啊国家啊这什么什么之是啥玩意?我让应用层看看……应用层说应该是两句诗?”

TCP 最适合用于对时序不太关心的,且要求高可靠性的应用程序。

  • 万维网HTTP/HTTPS
  • 安全外壳(SSH
  • 电子邮件SMTP,IMAP / POP
  • 文件传输协议(FTP

UDP 最适合需要速度和效率的应用程序。

  • 串流影片
  • 线上游戏
  • 现场直播
  • 域名系统(DNS
  • 互联网协议语音(VoIP
  • 普通文件传输协议(TFTP

一个问题:什么是协议

协议实际上就是一种约定。好比说,我们做一个石头剪刀布的游戏,我们约定好:石头>剪刀、剪刀>布、布>石头,以此作为游戏规则。我们所有人都遵循这个约定,那么就不需要任何的多余的沟通便可以完成这个游戏。而这种方式形成的约定实际上就是一种协议了。

模型

TCP/IP模型

TCP/IP其实也可以指代一个遵循TCP/IP的协议族,我们后面会说到,我们先来看这个模型。

TCP/IP的四层模型:

  1. 应用层,在这一层上的有HTTP、DNS、FTP、SSH等。
  2. 传输层,在这一层上的有TCPUDP等。
  3. 网络层,在这一层上的有IPARP等。
  4. 网络接口层,在这一层上的有以太网、PPP等。

编者注:TCP/IP模型是由 OSI 模型演化而来,TCP/IP 模型将 OSI 模型由七层简化为五层(一开始为四层),应用层、表示层、会话层统一为应用层。

如果从客户端到来一个请求:

  1. 服务器端接收到客户端的SYN报文,返回SYN+ACK报文,服务器端进入SYN_RCVD状态。
  2. 服务器端收到客户端返回的ACK应答后,连接建立,进入ESTABLISHED状态。
  3. 服务器端的数据传输完毕,给客户端发送FIN报文,进入FIN_WAIT_1状态。
  4. 服务器端接收到客户端返回的ACK应答后,进入FIN_WAIT_2状态。
  5. 服务器端接收到客户端的FIN报文,接着返回一个ACK应答,等待连接关闭,进入TIME_WAIT状态。
  6. 服务器端经过2MSL时间后进入CLOSED状态,此时连接关闭。

至于客户端,在每个阶段也有各自的状态,下图表示了TCP状态迁移的过程:

别太较真,图一乐


TCP/IP 协议族里重要的一点就是分层。把 TCP/IP 层次化是有好处的。比如,如果互联网只由一个协议统筹,某个地方需要改变设计时,就必须把所有部分整体替换掉。而分层之后只需把变动的层替换掉即可。把各层之间的接口部分规划好之后,每个层次内部的设计就能够自由改动了。

值得一提的是,层次化之后,设计也变得相对简单了。处于应用层上的应用可以只考虑分派给自己的任务,而不需要弄清对方在地球上哪个地方、对方的传输路线是怎样的、是否能确保传输送达等问题。

数据链路层

数据链路层是负责接收 IP 数据包并通过网络发送,或者从网络上接收物理帧,抽出 IP 数据包,交给网络层(IP层)。

常见的接口层协议有:

Ethernet 802.3、Token Ring 802.5、X.25、Frame relay、HDLC、PPP ATM等。

网络层

负责相邻计算机之间的通信。其功能包括三方面。

  • 处理来自传输层的分组发送请求,收到请求后,将分组装入 IP 数据报,填充报头,选择去往信宿机的路径,然后将数据报发往适当的网络接口。

  • 处理输入数据报:首先检查其合法性,然后进行寻径–假如该数据报已到达信宿机,则去掉报头,将剩下部分交给适当的传输协议;假如该数据报尚未到达信宿,则转发该数据报。

  • 处理路径、流控、拥塞等问题。

网络层包括:IP(Internet Protocol) 协议、ICMP(Internet Control Message Protocol)控制报文协议、ARP(Address Resolution Protocol) 地址转换协议、RARP(Reverse ARP) 反向地址转换协议。

ARP 是正向地址解析协议,通过已知的 IP,寻找对应主机的 MAC 地址。

RARP 是反向地址解析协议,通过 MAC 地址确定 IP 地址。比如无盘工作站还有 DHCP 服务。

IP 是网络层的核心,通过路由选择将下一条IP封装后交给接口层。IP数据报是无连接服务。

ICMP 是网络层的补充,可以回送报文。用来检测网络是否通畅。

Ping 命令就是发送 ICMPecho 包,通过回送的 echo relay 进行网络测试。

传输层

提供应用程序间的通信。其功能包括:一、格式化信息流;二、提供可靠传输。

传输层协议主要是:传输控制协议 TCP(Transmission Control Protocol) 和用户数据报协议 UDP(User Datagram protocol)。

应用层

向用户提供一组常用的应用程序,比如电子邮件、文件传输访问、远程登录等。远程登录 TELNET 使用 TELNET 协议提供在网络其它主机上注册的接口。TELNET 会话提供了基于字符的虚拟终端。文件传输访问 FTP 使用 FTP 协议来提供网络内机器间的文件拷贝功能。

应用层协议主要包括如下几个:FTP、TELNET、DNS、SMTP、NFS、HTTP

FTP(File Transfer Protocol)是文件传输协议,一般上传下载用FTP服务,数据端口是 20H,控制端口是 21H。

Telnet 服务是用户远程登录服务,使用 23H 端口,使用明码传送,保密性差、简单方便。

DNS(Domain Name Service)是域名解析服务,提供域名到 IP 地址之间的转换,使用端口 53。

SMTP(Simple Mail Transfer Protocol)是简单邮件传输协议,用来控制信件的发送、中转,使用端口 25。

NFS()Network File System)是网络文件系统,用于网络中不同主机间的文件共享。

HTTP(Hypertext Transfer Protocol)是超文本传输协议,用于实现互联网中的 WWW 服务,使用端口 80。

TCP模型

TCP协议作用

TCP协议位于协议栈的传输层。当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流TCP则把数据流分割成适当长度的报文段,最大传输段大小(MSS)通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)限制。之后TCP把数据包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。

TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。

  • 在数据正确性与合法性上,TCP用一个校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和;同时可以使用md5认证对数据进行加密。
  • 在保证可靠性上,采用超时重传和捎带确认机制。
  • 在流量控制上,采用滑动窗口协议,协议中规定,对于窗口内未经确认的分组需要重传。

在拥塞控制上,采用广受好评的TCP拥塞控制算法(也称AIMD算法)。 该算法主要包括三个主要部分:

  • 加性增、乘性减;

  • 慢启动;

  • 对超时事件做出反应。

TCP连接的建立

一些常见的标志位:

URG:指示报文中有紧急数据,应尽快传送(相当于高优先级的数据)。

ACK:确认序号(AN)有效。

PSH:接到后尽快交付给接收的应用进程。

RSTTCP连接中出现严重差错(如主机崩溃),必须释放连接,在重新建立连接。

SYN:处于TCP连接建立过程。

FIN:发送端已完成数据传输,请求释放连接。

后面有更详细的解释

TCP是一个面向连接的协议,在每一次传输数据前,客户端和服务端需要进行连接,这个链接就是著名的三次握手。

第一次:客户端向服务端发送一个 SYNSEQ=J 客户端序号)报文给服务器端,进入SYN_SEND状态。

第二次:服务器端收到SYN报文,回应一个SYNSEQ=K 服务端序号)ACK(ACK=J+1 确认号=客户端序号+1)报文,进入SYN_RECV状态。

第三次:客户端收到服务器端的SYN报文,回应一个ACK(ACK=K+1)报文,进入Established状态。

三次握手就很安全了吗?在三次握手过程中,Server发送SYN-ACK之后,收到ClientACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击是一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了。

能不能通过两次握手建立连接

其实是可以的,但那同时存在一个问题,我们无法在发送方和接收方两边都建立安全、稳定的连接。

什么是连接

RFC 793 - Transmission Control Protocol 文档中非常清楚地定义了 TCP 中的连接是什么,我们简单总结一下:用于保证可靠性和流控制机制的信息,包括 Socket、序列号以及窗口大小叫做连接。

what-is-TCP-connection

所以,建立 TCP 连接就是通信的双方需要对上述的三种信息达成共识,连接中的一对 Socket 是由互联网地址标志符和端口组成的,窗口大小主要用来做流控制,最后的序列号是用来追踪通信发起方发送的数据包序号,接收方可以通过序列号向发送方确认某个数据包的成功接收。

到这里,我们将原有的问题转换成了『为什么需要通过三次握手才可以初始化 Sockets、窗口大小和初始序列号?』,那么接下来我们就开始对这个细化的问题进行分析并寻找解释。

阻止重复历史连接的初始化

RFC 793 - Transmission Control Protocol 其实就指出了 TCP 连接使用三次握手的首要原因 —— 为了阻止历史的重复连接初始化造成的混乱问题,防止使用 TCP 协议通信的双方建立了错误的连接。

The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.

想象一下这个场景,如果通信双方的通信次数只有两次,那么发送方一旦发出建立连接的请求之后它就没有办法撤回这一次请求,如果在网络状况复杂或者较差的网络中,发送方连续发送多次建立连接的请求,如果 TCP 建立连接只能通信两次,那么接收方只能选择接受或者拒绝发送方发起的请求,它并不清楚这一次请求是不是由于网络拥堵而早早过期的连接。

所以,TCP 选择使用三次握手来建立连接并在连接引入了 RST 这一控制消息,接收方当收到请求时会将发送方发来的 SEQ+1 发送给对方,这时由发送方来判断当前连接是否是历史连接:

  • 如果当前连接是历史连接,即 SEQ 过期或者超时,那么发送方就会直接发送 RST 控制消息中止这一次连接;
  • 如果当前连接不是历史连接,那么发送方就会发送 ACK 控制消息,通信双方就会成功建立连接;

使用三次握手和 RST 控制消息将是否建立连接的最终控制权交给了发送方,因为只有发送方有足够的上下文来判断当前连接是否是错误的或者过期的,这也是 TCP 使用三次握手建立连接的最主要原因

tcp-recovery-from-old-duplicate-syn

ACK:确认序号(AN)有效。

RSTTCP连接中出现严重差错(如主机崩溃),必须释放连接,在重新建立连接。

SYN:处于TCP连接建立过程。

在上图的过程中,发送方SEQ=90的历史连接请求被接收到并被服务器做出应答,但此时发送方的SEQ已经增长为100,发送方就可以知道这是历史连接,通过RST告知接受方废弃该连接,从而避免这个连接被建立在一个已经超时废弃的连接之上。

初始序列号

另一个使用三次握手的重要的原因就是通信双方都需要获得一个用于发送信息的初始化序列号,作为一个可靠的传输层协议,TCP 需要在不稳定的网络环境中构建一个可靠的传输层,网络的不确定性可能会导致数据包的缺失和顺序颠倒等问题,常见的问题可能包括:

  • 数据包被发送方多次发送造成数据的重复;
  • 数据包在传输的过程中被路由或者其他节点丢失;
  • 数据包到达接收方可能无法按照发送顺序;

为了解决上述这些可能存在的问题,TCP 协议要求发送方在数据包中加入『序列号』字段,有了数据包对应的序列号,我们就可以:

  • 接收方可以通过序列号对重复的数据包进行去重;
  • 发送方会在对应数据包未被 ACK 时进行重复发送;
  • 接收方可以根据数据包的序列号对它们进行重新排序;

序列号在 TCP 连接中有着非常重要的作用,初始序列号作为 TCP 连接的一部分也需要在三次握手期间进行初始化,由于 TCP 连接通信的双方都需要获得初始序列号,所以它们其实需要向对方发送 SYN 控制消息并携带自己期望的初始化序列号 SEQ,对方在收到 SYN 消息之后会通过 ACK 控制消息以及 SEQ+1 来进行确认。

basic-4-way-handshake

如上图所示,通信双方的两个 TCP A/B 分别向对方发送 SYNACK 控制消息,等待通信双方都获取到了自己期望的初始化序列号之后就可以开始通信了,由于 TCP 消息头的设计,我们可以将中间的两次通信合成一个,TCP B 可以向 TCP A 同时发送 ACKSYN 控制消息,这也就帮助我们将四次通信减少至三次。

A three way handshake is necessary because sequence numbers are not tied to a global clock in the network, and TCPs may have different mechanisms for picking the ISN’s. The receiver of the first SYN has no way of knowing whether the segment was an old delayed one or not, unless it remembers the last sequence number used on the connection (which is not always possible), and so it must ask the sender to verify this SYN. The three way handshake and the advantages of a clock-driven scheme are discussed in [3].

除此之外,网络作为一个分布式的系统,其中并不存在一个用于计数的全局时钟,而 TCP 可以通过不同的机制来初始化序列号,作为 TCP 连接的接收方我们无法判断对方传来的初始化序列号是否过期,所以我们需要交由对方来判断,TCP 连接的发起方可以通过保存发出的序列号判断连接是否过期,如果让接收方来保存并判断序列号却是不现实的,这也再一次强化了我们在上一节中提出的观点 —— 避免历史错连接的初始化。

连接的断开

一个TCP完整的断开需要进行四次挥手。

第一次:客户端向服务端发送 FIN + ACK 报文,同时携带序号为 X。 客户端进入 FIN-WAIT1

第二次:服务器端回复 ACK 报文。附带序号Z和确认序号X+1,表示服务器已经接受到了客服端的报文。但是由于服务器可能还在处理事务,因此,报文并不会携带FIN标志。状态:CLOSE WAIT

第三次:在一段时间之后,服务器已经处理完毕,发送带有 FINACK的报文,序号为Y,确认序号为 X + 1 。状态: ACK-LAST

第四次:客户端发送ACK报文,序号为 X+1,确认号Y+1 。 客户端进入: TIME_WAIT。服务端进入CLOSE(初始状态)

为什么建立连接是三次握手,而关闭连接却是四次挥手呢?

这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACKSYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACKFIN一般都会分开发送

打个不太恰当的比方,你点击关机按钮,相当于你向电脑发送FIN,但其实你电脑还有一些程序在运行,不过电脑会立即响应,进入关机阶段,相当于想你发送了ACK,然后他还会告诉你哪些程序需要被关闭,可以理解为又向你发送了一部分必要的数据,等待这些程序也被系统关闭后,电脑完成关机流程,黑屏,相当于向你发送了FIN,你发现电脑完成了关机、不再有任何响应,于是合上电脑起身离开,相当于发送了ACK(最后这个ACK有点牵强)

UDP模型

UDPUser Datagram Protocol)是一个简单的面向消息的传输层协议,尽管UDP提供标头和有效负载的完整性验证(通过校验和),但它不保证向上层协议提供消息传递,并且UDP层在发送后不会保留UDP 消息的状态。因此,UDP有时被称为不可靠的数据报协议。如果需要传输可靠性,则必须在用户应用程序中实现。

UDP使用具有最小协议机制的简单无连接通信模型。UDP提供数据完整性的校验和,以及用于在数据报的源和目标寻址不同函数的端口号。它没有握手对话,因此将用户的程序暴露在底层网络的任何不可靠的方面。如果在网络接口级别需要纠错功能,应用程序可以使用为此目的设计的传输控制协议(TCP)。

综上所述:UDP是基于IP的简单协议,不可靠的协议。

UDP的优点:简单,轻量化。

UDP的缺点:没有流控制,没有应答确认机制,不能解决丢包、重发、错序问题。

这里需要注意一点,并不是所有使用UDP协议的应用层都是不可靠的,应用程序可以自己实现可靠的数据传输,通过增加确认和重传机制,所以使用UDP 协议最大的特点就是速度快。

PING

我们经常使用ping命令来测试两台主机之间TCP/IP通信是否正常, 其实ping命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包, 如果数据包是否到达的消息及时反馈回来,那么网络就是通的。

ping命令是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接。ping命令是使用 IP 和网络控制信息协议 (ICMP),因而没有涉及到任何传输协议(UDP/TCP) 和应用程序。它发送ICMP回送请求消息给目的主机。

ICMP协议规定:目的主机必须返回ICMP回送应答消息给源主机。如果源主机在一定时间内收到应答,则认为主机可达。

UDP洪水

UDP 洪水是一种拒绝服务攻击,攻击者将大量用户数据报协议(UDP) 数据包发送到目标服务器,旨在让该设备的处理和响应能力无力承担。由于UDP 洪水攻击,保护目标服务器的防火墙也可能不堪重负,导致对正常流量拒绝服务。

UDP 洪水攻击的工作原理

UDP 洪水的工作原理主要是利用服务器响应发送到其端口之一的UDP 数据包时所采取的步骤。在正常情况下,服务器在特定端口上收到UDP 数据包时,将通过以下两个步骤进行响应:

服务器首先检查是否有任何当前侦听指定端口请求的程序正在运行。

如果该端口上没有程序正在接收数据包,则服务器将以ICMP (ping) 数据包作为响应,以告知发送方目标不可达。

UDP洪水就好比酒店接待员转接呼叫的情况。首先,接待员接到电话,呼叫者要求将其连接到特定客房。然后,接待员需要查看所有房间的列表,以确保客人在客房内,并愿意接听电话。如果接待员了解到客人没有接听电话,他们就必须重新接听电话,并告诉呼叫者客人不会接听电话。如果所有电话线路都突然同时发出类似请求,他们很快就会变得不堪重负。

由于目标服务器利用资源来检查并响应每个接收到的UDP 数据包,当收到大量UDP 数据包时,目标资源会很快耗尽,从而导致对正常流量拒绝服务。

如何防护UDP 洪水攻击?

大多数操作系统限制ICMP 数据包的响应速率,部分原因是为了中断需要ICMP 响应的DDoS 攻击。这种防护措施的一个缺点是,在攻击期间,合法数据包也可能在此过程中被过滤。如果UDP洪水的大小足以使目标服务器的防火墙的状态表饱和,则在服务器级别发生的任何防护都将是不够的,因为瓶颈将发生在目标设备的上游。

详细的标志位

URG:此标志表示TCP包的紧急指针域有效,用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据;

ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0;

PSH:这个标志位表示Push操作。所谓Push操作就是指在数据包到达接收端以后,立即传送给应用程序,而不是在缓冲区中排队;

RST:这个标志表示连接复位请求。用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包;

SYN:表示同步序号,用来建立连接。SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1,ACK=0;连接被相应的时候,SYN=1,ACK= 1;这个标志的数据包经常被用来进行端口扫描。扫描者发送一个只有SYN的数据包,如果对方主机响应了一个数据包回来,就表明这台主机存在这个端口;但是 由于这种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全的主机将会强制要求一个连接严格的进行 TCP的三次握手;

FIN:表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志位的TCP数据包后,连接将被断开。这个标志的数 据包也经常被用于进行端口扫描。当一个FIN标志的TCP数据包发送到一台计算机的特定端口,如果这台计算机响应了这个数据,并且反馈回来一个RST标志 的TCP包,就表明这台计算机上没有打开这个端口,但是这台计算机是存在的;如果这台计算机没有反馈回来任何数据包,这就表明,这台被扫描的计算机存在这 个端口。

参考

https://blog.csdn.net/freekiteyu/article/details/72236734

https://www.jianshu.com/p/dac7b8bdb682

https://draveness.me/whys-the-design-TCP-three-way-handshake/