计算机网络——传输层

计算机网络——传输层

传输层

传输层最主要的两个协议就是TCP和UDP。

寻址

TCP/UDP协议和IP协议都有一个共同的功能,即寻址。回顾一下,IP协议只是将分组报文分发到了不同主机(更准确的说是网络接口,因为一台主机可能装了多个网卡,而网卡才是目的地)。很明显,还需要其他更细粒度的寻址将报文发送到主机中指定的应用程序,因为同一台主机上可能有多个应用程序在使用网络。

TCP协议和UDP协议使用的地址叫做“端口号",这就是用来区分同一台主机中不同应用程序的。TCP和UDP协议有时候也称作端到端传输协议(end-to-end transport protocol),因为它们将数据"从一个应用程序传输到另一个应用程序",而IP协议只是将数据从”一台主机传输到另一台主机"

多路复用与多路分解

一台设备可能同时有多个进程在于网络交换数据,一个数据段到了传输层之后,需要被定向到对应的套接字中。

在接收端,将传输层报文段定向到适当的套接字的工作成为多路分解。

在发送端,从不同套接字中手机数据块,并未每个数据块封装上对应头部信息从而生成报文端,然后将报文段传递到网络层的工作成为多路复用。

TCP(Transmission Control Protocol)

TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送。

TCP建立连接


TCP关闭连接


TCP报文格式

  • 源端口号和目的端口号各占2个字节(结合IP头部的源IP地址,目的IP地址,就已经构成了简单地TCP连接)

  • 序号seq(这个报文段的第一个数据字节序号),序号范围是:0-232-1(4个字节,32位,即就是:4294967296)个序号。序号增加到232-1后,下一个序号又回到0。也就是说:序号使用mod运算。TCP是面向字节流的,在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。即本报文段所发送的数据的第一个字节的序号,例如:一报文段的序号字段值是301,而携带的数据共有100字节,这就说明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(有的话)的数据序号应当从401开始,即下一个序号字段值应为401,这个字段也叫做:报文段序号。

  • 确认号ack(4个字节) 是期望收到对方下一个报文段的第一个数据字节的序号。例如:B正确收到了A发送过来的一个报文段,A的序号字段值是501,而数据长度是200字节(501-700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。总之:若确认号 = N,则表明:到序号N-1为止的所有数据都已正确收到。这种机制被称为“累积确认(cumulative acknowledgment)”

  • 接受窗口 用户流量控制,只是接收方愿意接受的字节数量。

  • 数据偏移(也称为:头部长度),由于首部中还有长度不确定的选项字段,因此数据偏移是必要的,因为单位是32位字(即就是4字节),占4位(最大是15,也就是15*4 = 60个字节),接下来就是6位的保留,必须全部为0。

  • 6个标志位

    • URG为1是,紧急指针有效,告诉系统此报文段中有紧急数据,应当尽快传送(高优先级数据),而不要按原来的排队顺序来传送,例如:我们运行了一个程序,但是里面是死循环,程序一直都不退出,我们要让程序退出,键入中断命令(Control + C),如果不使用紧急数据,那么这两个字符将在接受TCP缓存的末尾,也就是只有等所有的数据都被处理完毕后这两个字符才被交付到接受方的应用进程,也就是说:我们的程序一直在死循环着,但:如果我们使用紧急指针,发送方就把紧急数据插入到本报文段数据的最前面,仅接着执行。window下的任务管理系统也是这个原理。

    • ACK为1时,确认号有效,当ACK = 0时,确认号无效,TCP规定:在连接建立后所有传送的报文段都必须把ACK置1。

    • PSH为1时,当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP就可以使用推送psh操作。这时,发送方TCP把PSH置1,并立即创建一个报文段发送出去。接受方TCP收到PSH = 1的报文段,就尽快的交付给接收应用进程,而不再等待到整个缓存都填满了后再向上交付。

    • RST为1时,表示TCP连接中出现严重差错(由于主机崩溃或这其他原因),必须释放连接,然后在重新建立运输连接。RST置1还用来拒绝一个非法的报文段或拒绝打开一个连接。

    • SYN为1时,用来发起一个连接,在连接建立时用来同步序号。当SYN = 1而ACK = 0时,表明这是一个请求建立连接报文段。对方若同意建立连接,则应在响应的报文段中使用SYN = 1和ACK = 1。因此:SYN置为1就表示一个连接请求或连接接受报文。

    • FIN为1时,表示此报文段的发送方的数据已发送完毕,用来发起关闭连接操作。

  • 窗口尺寸(2字节),是[0, 2^16 - 1]之间的整数。窗口指的是发送本报文段的一方的接受窗口(并不是自己的发送窗口),窗口值告诉对方:从本报文段首部中的确认号算起,接受方目前允许发送的数据量。之所以要有这个限制,是因为接受方的数据缓存空间是有限的。接受方的数据缓存空间直接影响了发送发TCP报文段窗口数值的大小,如:设接受方发送的确认号是701,窗口字段是1000。这就说明:下一次,从701开始,发送方发送此报文段可以发送的范围是701-1700(1700最大,不一定发送这么多)

  • 检验和 占2字节。检验和字段检验的范围包括首部和数据这两部分。检验数据在发送端到接收端之间是否发生了变化。如果接收方检测到检验和有差错,则TCP段会被直接丢弃。

  • 紧急指针,占2字节。紧急指针仅在URG = 1时才有意义,(紧急数据结束后就是普通数据),紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据处理完后,TCP就告诉应用程序恢复到正常操作。值得注意的是:即使窗口为0时,也可以发送紧急数据。

UDP(User Datagram Protocol)

UDP协议又称为用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。
它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成,提供面向事务的简单不可靠信息传送服务。UDP 协议基本上是IP协议与上层协议的接口。

一般来说,TCP对应的是可靠性要求高的应用,而UDP对应的则是可靠性要求低、传输经济的应用。

在这里插入图片描述
UDP报文格式

  • 源端口号&目标端口号
  • 数据报长度
  • 报文长度 包括报头和数据部分在内的总字节数。因为报头的长度是固定的,所以该域主要被用来计算可变长度的数据部分。这与TCP协议是不同的,后者要求必须具有校验值。
  • 校验和 UDP协议使用报头中的校验值来保证数据的安全。校验值首先在数据发送方通过特殊的算法计算得出,在传递到接收方之后,还需要再重新计算。如果某个数据报在传输过程中被第三方篡改或者由于线路噪音等原因受到损坏,发送和接收方的校验计算值将不会相符,由此UDP协议可以检测是否出错,出错的话直接丢弃数据。

TCP支持的应用协议主要有:HTTP、Telnet、FTP、SMTP等;UDP支持的应用层协议主要有:NFS(网络文件系统)、SNMP(简单网络管理协议)、DNS(主域名称系统)、TFTP(通用文件传输协议)等。

区别

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

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

“好的。”

“苟。这是第一个字。”

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

“利。这是第二个字。”

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

“国。这是第三个字。”

“国。这是第三个字。”

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

“家……”……“我讲完了。”

“好的。我听完了。”

“好的。”


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

“苟利国家生死以…”

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


选择传输层协议由以下几个维度来考虑:可靠性、吞吐量、实验性、安全性。

TCP协议

TCP协议能够检测和恢复IP层提供的主机到主机的信道中可能发生的报文丢失,重复以及其他错误。TCP协议提供了一个可信赖的字节流(reilable byte-stream)信道。使用TCP协议在很多方面都与文件的输入输出(I/O)相似。实际上,由一个程序写入的文件再由另一个程序读取就是一个TCP连接的适当模型。

TCP可靠性机制

由于IP是个不可靠的协议,那么在数据传输路径上,第一个可以确保可靠传输问题的地方就是应用程序所在主机的TCP层。

可靠性就代表着数据无差错、不丢失、不重复和有序性。

  • 校验和
    • 用于检测在一个传输分组中的比特错误。
  • 定时器
    • 用户超时/重传一个分组。
  • 序号
    • 用于为从发送方流向接收方的数据分组按顺序编号,保证接收数据有效性及检测出冗余副本。
  • 确认
    • 接收方告诉发送方一个分组或一组分组已被正确接收。确认报文通常携带着被确认的分组或多个分组序号。
  • 否定确认
    • 接收方告诉发送方某个分组未被正确接收。
  • 窗口、流水线
    • 用于增加信道的吞吐量
最大报文长度MSS

MSS: Maximum Segment Size 最大报文段长度

MSS是TCP数据包每次能够传输的最大数据分段。
为了达到最佳的传输效能,TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往用MTU值代替(需要减去IP数据包包头的大小20Bytes和TCP数据段的包头20Bytes)所以一般MSS值1460
通讯双方会根据双方提供的MSS值得最小值确定为这次连接的最大MSS值。
注:最大报文段长度MSS这个名词很容易引起误解。MSS是TCP报文段中的数据字段的最大长度。数据字段加上TCP首部才等于整个的TCP报文段。

所以MSS并不是TCP报文段的最大长度,而是:MSS=TCP报文段长度-TCP首部长度。

消息确认

当接收端TCP成功接收到TCP报文段之后,会在一个短暂的时间间隔内(并不是在成功接收到报文的那一刻),向发送端发送一个表明该报文段已经被成功接收确认消息(Acknowledgement)。

差错控制

超时重传:发送端具有一个存储报文段的缓冲区(Buffer),我们一般称为发送端窗口(Sender Window),用于存放已经发送但是尚未接受到确认的报文段。如果接收到确认,会将相应的报文段从发送端窗口中移除。如果在一定的超时时限内没有接收到确认消息,会认为相应的报文段发送失败,此时发送端TCP会从发送端窗口中提取相应的报文段进行重新发送。

  • TCP重传又分为超时重传和快速重传两种。
    • 超时重传 超时重传的时间RTO(retransmission timeout),是根据若干次的RTT计算平均而来(有一个较复杂的计算算法),会根据网络环境的变化而动态调整;每次发送数据后到达RTO时间,如果ACK还没到达,就会进行超时重传,如果重传之后还没收到ack,下次重传的RTO值就会翻倍(乘以2),知道重传到达系统设置的重传次数,然后就会关闭连接;默认情况下,Windows主机默认重传5次。大多数Linux系统默认最大15次。两种操作系统都可配置。
    • 快速重传 指接收方发现接收到的报文不是自己想要的报文,中间有漏掉的报文序列时,就会连续发送三个相同的ACK(请求丢失序列的报文)给发送方,发送方在收到连续三个相同的报文ACK的时候就会触发快速重传机制,发送丢失的报文;快速重传是对超时重传的一个补充,使得重传更加及时。

差错恢复:TCP的差错恢复机制有“回退N步(GBN)”、“选择重传(SR)”和“选择确认(selective acknowledgement SACK)”三种方法

  • 回退N步 发送方可以连续发送N个数据报,每次发送一个报文都会设置超时计时器,如果某个报文触发了超时重传,则发送方需要重传该报文之后的所有报文,接受方也必须丢弃该报文之后的所有报文。

  • 选择重传 发送方依然可以连续发送N个报文,只是在其中某个报文触发超时重传或者快速重传之后,发送方只发送丢失的那个报文段,接受方也不会丢弃之前接收的报文,会将出错报文之后的报文存放在缓冲区,等收到丢失报文之后在一起交给应用层。

SR接收方窗口太大困境,窗口长度必须小于或等于序号空间大小的一半。

  • 选择确认 允许接收方有选择性的确认失序报文,通知发送方只重发失序报文。连接的两方设备必须同时支持这一功能,通过连接时使用的SYN片段来协商是否允许SACK。
流量控制

如果过多的源同时以很快的速度发送大量的数据包,而此时接收方并没有如此高的接收数据的能力,因此极易导致网络的拥塞。所以,为了控制发送方的发送速度,防止发送方并考虑到受发送缓冲区大小的制约等,要求对发送方已发出但尚未经确认的帧的数目加以限制,同时使网络的传输效率得到提高,滑动窗口协议应运而生,它使得发送方可以在未收到确认的情况下,同时发送多个数据分组,由此大大提升了网络吞吐量。

简单的说,发送和接受方都会维护一个数据帧的序列,这个序列被称作窗口。发送方的窗口大小由接受方确定,目的在于控制发送速度,以免接受方的缓存不够大,而导致溢出,同时控制流量也可以避免网络拥塞。

滑动窗口

对于TCP会话的发送方,任何时候在其发送缓存内的数据都可以分为4类:

  • “已经发送并得到对端ACK的” 对应上图1部分
  • “已经发送但还未收到对端ACK的” 对应上图2部分
  • “未发送但对端允许发送的” 对应上图3部分
  • “未发送且对端不允许发送”。 对应上图4部分

“已经发送但还未收到对端ACK的”和“未发送但对端允许发送的”这两部分数据称之为发送窗口(中间两部分)。

下面是个滑动后的示意图(收到36的ack,并发出了46-51的字节)

在这里插入图片描述

  • 滑动窗口机制
    • 发送数据被确认时,窗口左侧向右侧移动,称为窗口合拢;

    • 接收端处理数据并释放接收缓存时,窗口右侧向右移动,称为窗口张开;

    • 若窗口左侧和右侧重合,此时窗口为0,不再发送数据;

TCP通过让发送方维护一个称为接收窗口的变量来提供流量控制。

在这里插入图片描述

考虑一种特殊的情况,就是接收方若没有缓存足够使用,就会发送零窗口大小的报文,此时发送放将发送窗口设置为0,停止发送数据。之后接收方有足够的缓存,发送了非零窗口大小的报文,但是这个报文在中途丢失的,那么发送方的发送窗口就一直为零导致死锁。

解决这个问题,TCP为每一个连接设置一个持续计时器(persistence timer)。只要TCP的一方收到对方的零窗口通知,就启动该计时器,周期性的发送一个零窗口探测报文段。对方就在确认这个报文的时候给出现在的窗口大小(注意:TCP规定,即使设置为零窗口,也必须接收以下几种报文段:零窗口探测报文段、确认报文段和携带紧急数据的报文段)。

拥塞控制

如果网络上的延时突然增加,那么,TCP对这个事做出的应对只有重传数据,但是,重传会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,于是,这个情况就会进入恶性循环被不断地放大。试想一下,如果一个网络内有成千上万的TCP连接都这么行事,那么马上就会形成“网络风暴”,TCP这个协议就会拖垮整个网络。

拥塞控制主要是三个算法:1)慢启动,2)拥塞避免,3)快速恢复。

慢启动 Slow Start

慢启动为发送方的TCP增加了另一个窗口:拥塞窗口(congestion window CWND)

刚刚加入网络的连接,一点一点地提速,不要一上来就像那些特权车一样霸道地把路占满。

慢启动的算法如下:

开始 —> cwnd = 2^0 = 1 (单位:MSS 最大报文段)

经过1个RTT(网络往返时间)后 —> cwnd = 2^1 = 2

经过2个RTT后 —> cwnd = 2^2 = 4

经过3个RTT后 —> cwnd = 2^3 = 8

此时有一个ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入“拥塞避免状态”

拥塞避免

一般来说ssthresh的值是65535,单位是字节,当cwnd达到这个值时后,进入用拥塞避免状态,算法如下:

当窗口中所有的报文段都被确认时,cwnd的大小加1,cwnd的值就随着RTT开始线性增加,这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。

收到ACK —> cwnd = cwnd + 1

这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。很明显,是一个线性上升的算法。

当丢包的时候,会有两种情况:

1)等到RTO(重传定时器)超时,重传数据包。TCP认为这种情况太糟糕,反应也很强烈。

sshthresh = cwnd /2

cwnd 重置为 1

进入慢启动过程

2)收到3个duplicate ACK时(乱序)就开启快速重传,而不用等到RTO超时。

cwnd = cwnd /2

sshthresh = cwnd

进入快速恢复状态——Fast Recovery

快速恢复

快速重传和快速恢复算法一般同时使用。快速恢复算法是认为,你还有3个Duplicated Acks说明网络也不那么糟糕,所以没有必要像RTO超时那么强烈。 注意,正如前面所说,进入Fast Recovery之前,cwnd 和 sshthresh已被更新:

cwnd = cwnd /2
sshthresh = cwnd
然后,真正的Fast Recovery算法如下:

cwnd = sshthresh + 3 (加3的原因是因为收到3个重复的ACK,表明有3个“老”的数据包离开了网络)
重传Duplicated ACKs指定的数据包
如果再收到 duplicated Acks,那么cwnd = cwnd +1
如果收到了新的Ack,那么,cwnd = sshthresh ,然后就进入了拥塞避免的算法了。

快速恢复首次出现在4.3BSD的Reno版本,也称之为Reno版的TCP拥塞控制算法。

快速恢复是TCP推荐的而非必需的构件。

提问:TCP既然是可靠传输协议,为何客户端还要实现消息重发、消息确认机制?

TCP是一个端对端协议,也就是说它自己要在对等实体之间提供可靠的传输机制。但是,认识到"端点"位于对等的TCP层,而不是对等的应用程序中是非常重要的。要求进行端到端确认的应用程序必须自身提供此项功能。

UDP协议

UDP除了校验和可以做简单的错误验证之外,没有任何上述TCP各种差错控制、流量控制、拥塞控制的机制。

它并不尝试对IP层产生的错误进行修复,它仅仅简单的扩展了IP协议“尽力而为best effort"的数据报服务,使得数据能在应用程序之间工作,而不是在主机之间工作。因此,使用了UDP协议的应用程序必须为处理报文丢失,顺序混乱等问题做好准备。

UDP协议会用自己的分组结构封装用户消息,它只增加了4个字段:源端口、目标端口、分组长度和校验和。这样,当IP把分组送达目标主机时,该主机能够拆开UDP分组,根据目标端口找到目标应用程序,然后再把消息发送过去。说到底,UDP仅仅是在IP层之上通过嵌入应用程序的源端口和目标端口,提供了一个“应用程序多路复用”机制。

套接字Socket

应用程序和网络直接的应用程序编程接口(API)被称为套接字(Socket)。
开发者可以控制套接字在应用层端的一切,但是对该套接字的传输层几乎没有控制权。

套接字是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

Socket=Ip address + port + TCP/UDP。

一个进程(网络应用)有一个或多个套接字,他相当于从网络向进程传递数据和从进程向网络传递数据的门户。

套接字分类

  • 流式套接字(SOCK_STREAM)
    流式套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。流式套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP协议。

  • 数据报套接字(SOCK_DGRAM)
    数据报套接字提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。

  • 原始套接字(SOCK_RAW)
    原始套接字(SOCKET_RAW)允许对较低层次的协议直接访问,比如IP、 ICMP协议,它常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以自如地控制Windows下的多种协议,能够对网络底层的传输机制进行控制,所以可以应用原始套接字来操纵网络层和传输层应用。比如,我们可以通过RAW SOCKET来接收发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以用来发送一些自定包头或自定协议的IP包。网络监听技术很大程度上依赖于SOCKET_RAW。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值