第6章 传输层(详解TCP的三次握手与四次挥手)

第6章 传输层

传输层简介

传输层为网络应用程序提供了一个接口,并且能够对网络传输提供了可选的错误检测、流量控制和验证功能。TCP/IP传输层包含很多有用的协议,能够提供数据在网络传输所需的必要寻址信息。但寻址和路由只是传输层的部分功能。tcp/ip的开发者知道你他们需要在网际层上添加另外一层,并通过这一层提供的额外必要特性来使用IP。传输层协议需要提供以下功能:

  • 为网络应用程序提供接口:也就是为应用程序提供访问网络的途径。设计者希望不仅仅能够向目的计算机传递数据,还能够向目的计算机上的特定程序传递数据。
  • 多路复用/多路分解机制:这里的多路复用表示从不同应用程序和计算机接收数据,再把数据传递到目的计算机上的接收程序。换句话说,传输层必须能够同时支持多个网络程序和管理传递给网际层的数据流。在接收端,传输层必须能够从网际层接收数据,把他转发到多个程序,这种功能被称为多路分解,它可以让一台计算机同时支持多个网络程序,比如一个WEB浏览器、一个E-mail客户端和一个文件共享应用程序。多路复用/多路分解的另一个作用是可以让一个应用程序同时保持与多台计算机的连接。
  • 错误检测、流量控制和验证:协议系统需要一种全面的机制来确保发送端与接收端之间的数据传输。

最后一项是变化最多的。质量保证通常会在收益与代价之间寻找平衡。精心的质量保证系统会提高传输的可靠性,但需要以增加网络流量和处理时间为代价。对于大多数应用程序来说,这种额外的保证并不值得。因此传输层提供了两种到达网络的方式,他们都具有支持应用程序所必须的接口和多路复用/多路分解功能,但在质量保证方面所采用的方法有很大不同,如下所示:

  • 传输控制协议(TCP):TCP提供了完善的错误控制和流量控制,能够确保数据正确传输,它是一个面向连接的协议。
  • 用户数据报协议(UDP):UDP只提供了非常基本的错误检测,用于不需要TCP精细控制功能的场合,它是一个无连接的协议。

面向连接的协议和无连接的协议

为了针对不同情况提供不同程序的质量保证,传输层提供了两种不同的协议原型

  • 面向连接的协议:会在通信计算机之间建立并维护一个连接,并且在通信过程中监视连接的状态。换句话说,通过网络传输的每个数据包都会有一个确认,发送端计算机会记录状态信息来确保每个数据包都被正确无误地接收了,并且在需要时会重发数据。当数据传输结束之后,发送端和接收端计算机会以适当方式关闭连接。
  • 无连接的协议:以单向方式向目的发送数据报,不承担通知目的计算机关于数据发送的职责。目的计算机接收到数据后也不需要向源计算机返回状态信息。

端口和套接字

在TCP/IP系统中,应用程序可以使用端口号通过TCP或UDP指定数据目的地端口是一个预定义的内部地址,充当从应用程序到传输层或是从传输层到应用程序之间的通路。

进一步观察传输层这种与应用程序相关的寻址体制,就会发现TCP和UDP数据实际是被发送到一个套接字上的。套接字是一个由IP地址和端口号组成的地址。例如,套接字地址111.121.131.141.21指向IP地址为111.121.131.141的计算机的端口21。

下面的例子里展示了一台计算机如何通过套接字访问目的计算机上的一个应用程序。

服务 TCP端口号 简要描述
tcpmux 1 TCP端口服务多路复用器
compressnet 2 管理工具
ftp 21 文件传输协议控制
ssh 22 安全shell
smtp 25 简单邮件传输协议
http 80 WWW服务
服务 UDP端口号 简要描述
echo 7 回显
discard 9 抛弃或空
domain 53 域名服务程序(DNS)
systat 11 用户
daytime 13 时间
qotd 17 每日引用
  1. 计算机A通过一个熟知的端口向计算机B上的应用程序发起一个连接。熟知端口是由互联网数字分配机构(IANA)分配给特定程序的端口。上表列出了一些熟知的TCP和UDP端口。熟知的端口与IP地址组合之后就构成了计算机A的目的套接字。连接请求包含着一个数据字段,告诉计算机B使用什么套接字向计算机A返回信息,这也就是计算机A的源套接字地址
  2. 计算机B通过熟知端口接收到来自计算机A的请求,向作为计算机A源地址的套接字发送一个响应。这个套接字就成为计算机B上的应用程序向计算机A上的应用程序发送消息的目的地址

多路复用/多路分解

套接字寻址系统使得TCP和UDP能够执行传输层另一个重要任务:多路复用和多路分解。多路复用是指多个来源的数据导向一个输出,而多路分解是把一个来源接收的数据发送到多个输出。

多路传输/多路分解分解让TCP/IP协议栈较低层的协议不必关心哪个程序在传输数据。与应用程序相关的操作都由传输层完成了,数据通过一个与应用程序无关的管道在传输层与网际层之间传递。

多路复用和多路分解的关键在于套接字地址。套接字的地址包含了IP地址与端口号,为特定计算机上的特定应用程序提供了一个唯一的标识。所有客户端计算机使用熟知的TCP端口21连接到FTP服务器,但针对每台个人计算机的目的套接字是不同的。类似地,运行于这台FTP服务器上全部网络应用程序都使用服务器的IP地址,但只有FTP服务程序使用由IP地址和TCP端口号21组成的套接字地址

理解TCP和UDP

本章前面提到,TCP是个面向连接的协议,提供了全面的错误控制和流量控制。UDP是个无连接协议,错误控制也简单得多。可以这样说,TCP是为了可靠性,而UDP是为了速度。必须要支持交互会话的应用程序,比如Talnet和FTP,就会使用TCP。而自己实现错误检测或不需要过多错误控制的应用程序会倾向于使用UDP。

软件开发人员在设计网络应用程序时可以选择使用TCP或UDP作为传输协议。UDP的控制机制虽然比较简单,但这并不是它的缺点。首先,较简单的质量控制并不一定意味着低质量。对于大多数应用程序来说,TCP提供的错误检测与控制是完全没有必要的。在一些需要控制错误和流量控制的情况下,有些开发人员更愿意在应用程序本身内提供这些控制功能,从而可以根据实际需要进行控制,并使用较简单的UDP进行网络访问。例如,应用层的远程过程调用RPC协议能够支持复杂的应用程序,但RPC开发人员有时倾向于在传输层使用UDP,并且利用应用程序提供错误控制和流量控制,而不是使用速度较慢的TCP连接

TCP:面向连接的传输协议

它包括以下重要特性:

  • 面向流的处理:TCP以流的方式处理数据。换句话说,TCP可以一个字节一个字节地接收数据,而不是一次接收一个预定义格式的数据块。TCP把接收到的数据组成长度不定的段,再传递到网际层。
  • 重新排序:如果数据以错误的顺序到达目的,TCP模块能够对数据重新排序来恢复原始顺序。
  • 流量控制:TCP的流量控制特性能够确保数据传输不会超过目的计算机接受数据的能力。由于现实世界里会有各种不同的应用环境,处理器速度和缓存区大小的差别也可能很大,所以这种流控制能力是非常重要的。
  • 优先级与安全:国防部对TCP的规范要求可以为TCP连接设置可选的安全级别和优先级,但很多TCP实现并没有提供这些安全和优先级特性。
  • 适当的关闭:TCP像重视建立连接一样重视关闭连接的工作,以确保在连接关闭之前,所有数据段都被发送和接收了。

1.TCP数据格式

  • 源端口(16位):分配给源计算机上的应用程序的端口号
  • 目的端口(16位):分配给目的计算机上的应用程序的端口号
  • 序列号(32位):当SYN标记不为1时,这是当前数据分段第一个字节的序列号;如果SYN的值是1,这个字段的值就是初始序列值(ISN),用于对序列号进行同步,这时第一个字节的序列号比这个字段的值大1(也就是ISN加1)
  • 确认号(32位):用于确认已经接收到的数据分段,其值是接收计算机即将接收的下一个序列号,也就是下一个接收到的字节的序列号加1。
  • 数据偏移(4位):这个字段表示报头的长度,也就是告诉接收端的TCP软件数据从何开始。这个值的单位是32位的字
  • 保留(6位):保留字段,为TCP将来的发展预留空间,目前必须全部是0。
  • 控制标记(分别占用1位):控制标记用于表示数据分段的特殊信息
    • URG: 为1时表示当前数据分段是紧急的,也会让“紧急指针”字段的值有意义。
    • ACK: 为1时表示“确认号”字段是有意义的。
    • PSH: 为1时让TCP软件把目前收到的全部数据都通过管道传递给接收应用程序
    • RST: 为1时会重置连接
    • SYN:为1时表示序列号将被同步,说明这是一个连接的开始。请参见稍后介绍的三次握手
    • FIN:为1时表示发送端计算机已经没有数据需要发送了。这个标记用于关闭一个连接
  • 窗口(16位):用于流量控制的参数。它定义了发送端计算机的发送序列号可以超过最后一个已确定序列号的数量。也就是说,发送方不必等待每个数据段被确认接收之后才发送下一个数据分段,允许已经确认接收的序列号与正在发送的序列号有一定的差别,但必须在适当范围之中
  • 校验和(16位):用于检验数据分段的完整性。接收端计算机会根据接收到的数据分段计算校验和,并且把结构与这个字段的值进行比较。TCP和UDP在计算校验和时包含一个具有IP地址的伪报头。
  • 紧急指针(16位):这是一个偏移量指针,指向标记紧急信息开始的序列号
  • 选项:指定一些可选设置中的某一项
  • 填充:额外填充的0,以确保数据从32位字的边界开始
  • 数据:数据分段中的数据

2.TCP连接

TCP的功能之一是为应用程序提供访问网络的接口。这个接口是通过TCP端口提供的,而为了通过端口提供连接,必须打开TCP与应用程序的接口。TCP支持以下两种打开状态。

  • 被动打开:某个应用程序进程通知TCP准备通过TCP端口接收连接,这样就会打开TCP到应用程序的连接,从而为参与连接请求做准备
  • 主动打开:程序要求TCP发起与另一台计算机(处于被动打开状态)的连接,这就是主动打开状态,实际上TCP可以对一个处于主动打开状态的计算机初发起连接,已解决两台计算机可能同时尝试建立连接的问题。

在通常情况下,想接收连接的应用程序(比如FTP服务器)会把自身及其TCP端口置于被动打开状态。在客户端计算机上,FTP客户端的TCP状态一般是关闭的,直到用户发起一个从FTP客户端到FTP服务器的连接,这对于客户端来说就是主动打开的。处于主动打开状态的计算机上的TCP软件会开始一些用于建立连接的信息交换,这种信息交换被称为“三次握手”,稍后详细介绍

TCP发送的数据分段的长度是不定的。在一个数据分段内,每字节数据都被分配一个序列号。接收端计算机必须为接收到的每个字节数据都发送一确认信号。因此TCP通信是一种传输与确认的系统。TCP报头中的“序列号”和“确认号”字段让通信的TCP软件能够定期更新传输的状态。

实际上,数据分段中并不是为每个字节都单独编了一个序列号。而是在报头的“序列号”字段指定了数据分段第一个字节的序列号。

如果数据分段被成功接收,接受端计算机会利用“确认号”字段告诉发送端计算机它接收到哪个字节。在确认消息中,“确认号”字段的值是已接收的最后一个序列号加1.换句话说,“确认号”字段中的值是计算机准备接收的下一个序列号。

3.建立连接

为了让序列/确认系统正常工作,计算机必须对序列号进行同步。换句话说,计算机B必须知道计算机A的初始化序列号(ISN)。计算机A也必须知道计算机B使用什么ISN开始传输数据。

这个序列号的同步过程被称为三次握手。三次握手总是发生在TCP连接建立的初期,其步骤如下:

  1. 计算机A发送一个数据分段,其中的参数是:
    SYN = 1
    ACK = 0
    序列号 = X (X是计算机A的ISN)
    处于主动打开状态的计算机(计算机A)发送一个数据分段,其中SYN为1,ACK为0.SYN是同步(syncchronize)的缩写,它表示在尝试建立一个连接。第一个数据分段的报头还包含初始序列号(ISN),标记了计算机将传输的第一个字节的序列号。也就是说,要发送给计算机B的第1个字节的序列号是ISN加1
  2. 计算机B接受到计算机A的数据分段,返回一个数据分段,其中的参数是:
    SYN = 1
    ACK = 1 (确认号字段将包含一个值)
    序列号 = Y (Y是计算机B的ISN)
    确认号 = M + 1 (其中M是从计算机A接收到的最后一个序列号)
  3. 计算机A向计算机B发送一个数据分段,确认收到计算机B的ISN:
    SYN = 0
    ACK = 1
    序列号 = 序列中下一个号码 (M+1)
    确认号 = N + 1 (其中N是从计算机B接收到的最后一个序列号)

在这三次握手完成之后,连接就被打开了,TCP模块就利用序列和确信机制发送和接收数据。

为什么需要“三次握手”

在谢希仁的《计算机网络》中是这样说的,为了防止已失效的连接报文段又发送到了服务器端,从而产生错误
在书中同时举了一个例子:“已失效的连接报文段”产生在这样一种情况下:client发出的第一个连接请求报文段并没有消失,而是在某个网络结点长时间的滞留了,以致于延误到释放以后的时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段之后,就误以为是client再次发过来的一个新的连接请求。假设没有“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立了,并一直等待client发来数据。这样,server的资源就白白浪费了。

4.TCP流量控制

TCP报头中的“窗口”字段为连接提供了一种流量控制机制,其目的是防止发送端计算机不要发送得太快,以避免接收端计算机来不及处理接收到的数据而导致数据丢失。TCP使用的流量控制方法被称为“滑动窗口”方法。接收端计算机利用“窗口”字段来定义一个超过最后一个已确认序列号的序列号“窗口”。在这个范围内的序列号才允许发送端计算机进行发送。发送端计算机在没有接收到下一个确认消息之前不能发送超过这个窗口的序列号。

5.关闭连接

当需要关闭连接时,计算机开始关闭过程,计算机A发送一个数据分段,其中的FIN标记设置为1。之后应用程序进入“结束--等待”状态。在这个状态中,计算机A的TCP软件继续接收数据分段,并处理已经在序列中的数据分段,但不再从应用程序接收数据了。当计算机B接收到FIN数据分段时,它返回对FIN的确认信息,然后发送剩余的数据分段,通知本地应用程序接收到了FIN消息。计算机B向计算机A发送一个FIN数据分段,计算机A会返回确认消息,连接就被关闭了。

四次挥手的表述

  1. 计算机A发送一个FIN标志,此时计算机A进入FIN_WAIT状态
  2. 计算机B收到了FIN报文段,向计算机A返回一个ACK字段,告诉A我同意你的关闭请求
  3. 计算机B继续处理剩余数据,处理完向A发送FIN报文段,请求关闭连接,同时B进入LAST_ACK状态
  4. 计算机A接收到B发送的FIN报文段,向B发送ACK报文段,然后主机1进入TIME_WAIT状态;主机B收到后,就关闭连接了。A等待2MSL后依然没有收到回复,A也可以关闭连接了。

UDP: 无连接传输协议

虽然UDP有时被认为没有错误检验功能,但实际上它能够执行基本的错误检验,因此,可以说UDP具有有限的错误检验功能。UDP数据报中包含一个检验和,接收端计算机可以利用它来检验数据的完整性(一般情况下,这个校验和检查是可选的,而且能够被接收端计算机禁用以加快对接收数据的处理)。UDP数据报中有个一个伪报头,包含了数据报的目的地址,从而提供了发现数据报错误传输的手段。另外,如果UDP接收模块接收到一个发给未激活或未定义UDP端口的数据报,它会返回一个ICMP消息,通知源计算机这个端口是不可到达的。

其次,UDP没有像TCP那样提供数据的重新排序功能。在大型网络上,数据分段可能会经过不同的路径,由于路由器缓存而产生明显延时,这时重新排序功能是非常有意义的。而在局域网上,虽然UDP没有重新排序功能,但一般不会导致不可靠的接收。

UDP协议的主要用途是把数据报传递给应用层。UDP协议的功能简单,其报头结构也很简单。UDP不会重新传输丢失或损坏的数据报、重新排列混乱的接收数据、消除重复的数据报、确认数据报的接收、建立或是终止连接。它主要是在程序不必使用TCP连接开销的情况下发送和接收数据报的一种方式。如果上述功能对于应用程序来说是必需的,它可以自己提供这些功能。

UDP头包含4个16位字段

  • 源端口: 这个字段占据UDP报头的前16位,通常包含发送数据报的应用程序所使用的UDP端口。接收端的应用程序利用这个字段的值作为发送响应的目的地址。这个字段是可选的。发送端的应用程序不是一定要把自己的端口写在这个字段上。如果发送端的应用程序不写入其端口号,就应该把这个字段全置0。显然,如果这个字段没有包含有效的端口地址,接收端的应用程序就不能发送响应。然后有时这可能正是我们想要的功能,比如单向消息就不需要响应
  • 目的端口:这16位字段包含的端口地址是接收端计算机上UDP软件使用的端口
  • 长度:这16位字典以字节为单位表示UDP数据报的长度。这个长度包括了UDP报头和UDP数据载荷。因为UDP报头的长度是8字节,所以这个值最小是8。
  • 校验和:这个16位字段可以校验数据在传输过程中是否损坏。校验和是对二进制数据串执行特殊计算而得到的结果。对于UDP来说,校验和是基于伪报头、UDP报头、UDP数据和填充的0而计算的。源计算机生成校验和,目的计算机对它进行检验,让客户端用程序能够判断数据报是否完整。

由于实际的UDP报头并不包含源IP地址或目标IP地址,数据报可能会被传输到错误的计算机或服务。校验和使用部分数据来自于从IP报头(被称为伪报头)提取的值,这个伪报头包含了目的IP地址信息,让接收段计算机能够判断UDP数据报是否被错误支付。

防火墙和端口

防火墙是一个系统,保护局域网不被来自Internet的未授权用户攻击。“防火墙”的基本特性就是阻断对特定TCP和UDP端口的访问。实际上,“防火墙”一词有时具有动词特性,表示关闭对端口的访问。

例如,为了发起与服务器的安全Shell(SSH)会话,客户端计算机必须向SSH的熟知端(TCP22)发起一个请求。如果担心外部入侵者会通过SSH访问我们的服务器,一种方法是配置服务器来停止使用端口22。这样一来,服务器就关闭了SSH的应用,但也禁止了局域网中的合法用户使用SSH来完成正常操作。

另一种方法是安装防火墙,并且配置防火墙来阻断对TCP端口22的访问,这样做的结果是,局域网中的用户能够在防火墙之内自由地访问服务器上的TCP端口22,而局域网之外的网络用户就不能访问服务器的TCP端口22,也就不能通过SSH访问服务器了。事实上,这时Internet上的用户不能通过SSH访问局域网中的任何计算机。

场景中使用SSH的TCP端口22作为示例。防火墙通常会阻断可能产生安全威胁的任何或全部端口。网络管理员一般会阻断对全部端口的访问,除了必须的端口,比如处理E-mail的端口。在连接Internet的计算机上,比如Web服务器,通常会在外部放置一个防火墙,从而避免对这台对这台计算机的访问导致对局域网的非法访问


2017/4/3 更新

昨晚在腾讯笔试题中又遇到了几道三次握手的题目,很遗憾没有做对,现再继续整理一下TCP通信过程,如图所示:

TCP通信过程包括三个步骤

TCP通信过程详细版

三次握手各个状态的解释如下:

  1. CLOSED:起始点,在超时或者连接关闭时候进入此状态,这并不是一个真正的状态,而是这个状态图假想起点。
  2. LISTEN:服务器端等待连接的状态,服务器经过socket,bind,listen函数之后进入此状态,开始监听客户端发过来的连接请求。此称为应用程序被动打开(等到客户端连接请求)
  3. SYN_SEND:第一次握手发生阶段,客户端发起连接。客户端调用connect,发送SYN给服务器端,然后进入SYN_SENT状态,等待服务器端确认。如果服务器端不能连接,则直接进入CLOSED状态。
  4. SYN_RCVD:第二次握手发生阶段,跟3对应,服务器端接收到了客户端的SYN,此时服务器从LISTEN状态进入SYN_RCVD状态,同时服务器回应一个ACK,然后再发送一个SYN即SYN+ACK给客户端。
  5. ESTABLISHED: 第三次握手阶段,客户端接收到服务器端的ACK包之后,也会发送一个ACK确认包,发送之后,客户端进入ESLABLISHED状态,表明客户端这边已经准备好了。TCP需要两边准备好了才可以进行数据运输。服务器端接收到客户端的ACK后会从SYN_RCVD状态转移到ESTABLISHED状态,就可以进行后面的数据运输了。所以,ESLABLISHED也可以说是一个数据传送状态。

四次挥手各种状态的解释如下:

  1. FIN_WAIT_1:第一次挥手。主动关闭的一方终止连接时,发送FIN给对方,此时进入到FIN_WAIT1状态,然后等待对方返回ACK。
  2. CLOSE_WAIT接收到FIN之后,被动关闭的一方进入此状态。具体动作是接收到FIN后,发送ACK。之所以叫CLOSE_WAIT可以理解为被动关闭的一方此时正在等待
  3. FIN_WAIT_2接收到被动方发出的ACK时,进入该状态
  4. LAST_ACK:被动方发起关闭请求,由状态2进入该状态,具体动作是发送FIN给主动关闭请求的一方
  5. CLOSEING:表示你发送FIN报文后,并没有收到对方的ACK报文,反而收到了对方的FIN报文。这种情况主要出现在双方几乎同时close一个socket,那么就出现了双方同时发送FIN报文的情况
  6. TIME_WAIT:共有三个状态会进入该状态
    • CLOSEING进入:客户端发起关闭请求,发送FIN之后等待服务器回应ACK,但此时服务器端同时也发起关闭请求,也发送了FIN,且客户端先收到FIN,后接收到ACK
    • FIN_WAIT_1进入:发起关闭后,发送了FIN,等待ACK的时候,正好服务器端发起请求,发送了FIN,这时客户端接收到了先前的ACK,也收到了对方的FIN,然后发送ACK,与CLOSEING进入的状态不同的是接收到FIN和ACK的先后顺序,先收到ACK,后收到FIN
    • FIN_WAIT_2进入:这是与上面两种状态不同的情况,主动方在完成自身发起的主动关闭请求后,接收到了对方发送过来的FIN,然后回应ACK

相关问题

为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

答:这是因为:虽然对方同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理说可以直接回到CLOSED状态;但是因为我们必须假想网络是不可靠的,你无法保证最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的socket可能会因为超时未收到ACK报文,而重发FIN报文,这个TIME_WAIT的作用就是用来重发可能丢失的ACK报文

为什么要有TIME_WAIT状态?

答:

  1. 防止上一次连接中的包,迷路重新出现,影响新连接(经过2msl,上一次连接中所有的重复包都会消失)
  2. 可靠的关闭TCP连接。在主动关闭后发送最后一个ACK,有可能丢失,这时被动方会重新发FIN,如果这时主动方处于CLOSED状态,就会响应rst而不是ack。所以主动方要处于TIME_WAIT状态,而不能是CLOSED。

参考链接:
TCP三次握手和Time-Wait状态
什么是2MSL
TCP的三次握手以及TCP状态转换图详解
TCP状态转换图详解


posted @ 2017-03-22 17:05  海枯  阅读(637)  评论(0编辑  收藏  举报