传输层概述
传输层是整个TCP/IP协议栈核心之一,位于网络层之上,应用层之下。利用网络层的服务,为上层应用层提供服务。与网络层类似,传输层也拥有面向连接的服务与无连接的服务两种
用途在于提供高效的可靠的,性价比高的数据传输
传输实体
完成传输层任务的硬件或软件
– 传输实体可以在操作系统的内核
– 可以以一个链接库的形式绑定到网络应用中
– 可以以一个独立的用户进程运行
– 甚至可以实现在网络接口卡(网卡)上
传输层与网络层的区别
网络层运行在由承运商操作的路由器上,因此用户无法真正控制网络层。对于丢包,高延迟等问题只能选择被动接受。传输层架设在网络层之上,允许用户控制服务质量
传输层原语独立于网络层原语,而网络层原语会因为网络的不同而不同。传输层的原语在向应用层传输的原语可以屏蔽掉这些不同,只提供标准,统一的原语。
原语
计算机进程的控制通常由原语完成。所谓原语,一般是指由若干条指令组成的程序段,用来实现某个特定功能,在执行过程中不可被中断。在操作系统中,某些被进程调用的操作,如队列操作、对信号量的操作、检查启动外设操作等,一旦开始执行,就不能被中断,否则就会出现操作错误,造成系统混乱。所以,这些操作都要用原语来实现 原语是操作系统核心(不是由进程,而是由一组程序模块组成)的一个组成部分,并且常驻内存,通常在管态下执行。原语一旦开始执行,就要连续执行完,不允许中断
传输层和网络层的作用范围不同,网络层负责把数据从源机送达到目的机(主机到主机 Host to Host)。传输层负责把数据送达到具体的应用进程或端口(End to End 端到端,end point端点即套接字socket和某个具体的应用程序绑定)
数据段TPDU
传输层处理的协议数据单元是TPDU(Transport Protocol Data Unit)即数据段(segment),是从传输实体发到对应端传输实体的信息
TPDU作为数据(载荷)被封装在分组(packet)中,通过网络层进行传输交换
常用协议
- 用户数据报协议(UDP:User Datagram Protocol)
- 传输控制协议(TCP:Transmission Control Protocol)
用户数据报协议 UDP
User Dataprogram Protocol
UDP是一个无连接的传输层协议,UDP传输的是数据段,无需建立连接,不提供数据的可靠传输。很多网络应用,例如DNS都采用了UDP。UDP传输的是UDP数据段
UDP数据段
数据段包括总长为64bits,共4部分,每部分16bits的数据段头和数据两个部分。
数据段头结构
Source Port 源端口/16bits | Destination Port 目的端口/16bits |
---|---|
UDP Length 数据段长度/16bits | UDP checksum 校验和/16bits |
第三个字段数据段长度表示包括段头和数据的总长度,UDP中校验和可能存在也可能不存在,不存在时校验和长度设为0.
UDP数据段头最重要的内容就是前两个字段源端口和目的端口,二者长度均为16bits,能表示的最大长度是65536,也就是能表示的端口数量是65536个,范围从0~65535。
端口定义
端口号 | – |
---|---|
<=1023(知名端口) | 用于公共应用(保留,全局分配,用于标准服务器),只能用于特权用户,比如UNIX的root用户启动标准80服务。由IANA分配,目前已经使用700多个 |
1024~49151 | 用户端口/非特权用户端口,可以通过IANA注册(例如BT使用了6881-6887的端口) |
>=49152 | 动态端口,私人端口(其中包括自由端口:free port,由本地分配,并且动态随机生成的端口号,访问网站时操作系统会随机产生一个自由端口用于访问) |
UDP校验和
UDP校验和计算方式是将IP伪头部,UDP头部和数据按照二进制每行16位的格式排列,然后对这些排列好的数据进行补码相加求和,再对得到的结果进行求反码,最终得到的结果就是校验和
TCP/UDP伪头部(pseudo header)
接收方在接收到数据段后利用其中的校验和以及其他部分数据经过计算最终得到的结果每个位应该全部为1,如果出现0,证明传输过程中发生错误。
在计算校验和的过程中使用了属于网络层的IP地址,这破坏了分层原则
UDP提供端点标识,端到端的数据传输
不提供差错检测和可靠传输,但简洁高效
通信模型
端点
端点就是所说的套接字(Socket),一个套接字包括;两个内容:IP地址和端口号。可以写成(IP,Port)。
通信模型-通信五元组
通信五元组由源端点,目的端点和协议组成,其中源端点和目的端点包含IP地址和端口,协议可以是TCP或UDP
一些已分配的知名端口
Port | Protocol | Use |
---|---|---|
21 | FTP | File Transfer |
23 | Telnet | Remote login |
25 | SMTP | |
69 | TFTP | Trivial file transfer protocol |
79 | Finger | Looking information about a user |
80 | HTTP | World Wide Web |
110 | POP-3 | Remote email access |
119 | NNTP | USENET news |
不同于交换机上的端口(Interface接口),此端口非彼端口.
TCP数据段
TCP-传输控制协议
Transmission Control Protocol
是专门为了在不可靠的网络上提供可靠的端到端的字节流而设计的。TCP必须动态地适应不同的拓扑、带宽、延迟、分组大小和其它的参数,并且当有错误的时候,能够足够健壮
支持TCP的机器都有一个TCP实体,或者是用户进程,或者是操作系统内核。都可以管理TCP流跟IP层接口
发方:封装
TCP实体接收本地进程的用户数据流,将其分割成不超
过64kB的分片(实践中,通常分割成1460字节,以通过
以太网传输)
收方:解封装
当包含TCP数据段的报文到达某台机器的时候,被提交
给传输实体,传输实体将其重构出原始的字节流
- TCP连接上的每个字节都有它自己独有的32位序列号
- 收发双方的TCP实体以数据段的形式交换数据
- 一个数据段包括20字节的头部(不包括可选项)和数据域(0或更多字节)
TCP软件决定数据段的大小,有两个因素限制了数据段的长度:
- TCP数据段必须适合IP的65515(65535B-20B)的载荷限制(65535B是IP分组最大长度,20是IP分组头部固定长度,65515就是IP分组净载荷)
- 每个TCP数据段必须适合于下层网络的 MTU (如,1500 字节以太网载荷大小)
- TCP使用的基本协议具有动态窗口大小的滑动窗口协议
(sliding window protocol)
TPDU TCP数据段
源端口和目的端口字段
标明了一个连接的两个端点,是通信五元组中的两个重要元素,用来跟踪同一时间内通过网络的不同会话。一般每个端口对应一个应用程序
序列号 – 字节号 (32 位)
表示一个字节的编号,其中最特殊的是初始序列号ISNs(initial sequence numbers ):随机产生的
确认号
期望接收的字节号 (32位),在TCP中为了保证可靠传输,才哟过了肯定确认重传技术,确认号就是用于肯定确认重传
TCP段头长度
单位32位(4字节),含义与IP的段头长度完全一致
保留域/字段
即图中灰色部分,现在也开始逐步使用(进行拥塞控制等)
控制比特
URG,ACK,PSH,RST,SYN,FIN共6部分,每部分1byte,称作控制比特
URG
当紧急指针使用的时候,URG被置为1。紧急指针是一个对于当前序列号的字节偏移量,标明紧急数据从哪里开始
– 当URG=1时,表明有紧急数据,必须首先处理
– 与紧急指针配合使用
– 收方收到这样的数据后,马上处理,处理完后恢复正常操作
– 即使win=0,也可以发送这样的紧急数据段
ACK
1表示确认号有效,0表示确认号无效
PSH
表示这是带有PUSH标志的数据接收方收到这样的数据,应该立刻送到上层,而不需要缓存它
RST
被用来重置一个已经混乱的连接
SYN
用在连接建立的过程
– SYN=1,ACK=0:连接请求
– SYN=1,ACK=1:连接接受
FIN
被用来释放连接,它表示发送方已经没有数据要传输了,但是可以继续接收数据
窗口尺寸
为了避免收方被大量涌入数据所淹没,TCP实体进行了流控(Flow Control)。通常使用可变长的滑动窗口来完成流控。所以第十二个字段用16位来表示窗口尺寸
告诉对方可以发送的数据字节数(从确认字节号
开始(决定于接收方)
校验和
与UDP中的校验和是一样的,唯一区别在于协议位置的编号不一样
紧急指针
和URG数据段配合使用,指明了紧急数据
选项域(可选)
提供了一种增加基本头没有包含内容的方法
TCP三次握手建立连接
TCP提供的是面向连接的服务,TCP数据段的传输是在TCP链接上进行的。而TCP连接是三次握手建立的
TCP连接的建立
- 一方(server)被动地等待一个进来的连接请求
- 另一方(the client)通过发送连接请求,设置一些参数(第一次握手)
- 服务器方回发确认应答(第二次握手)
- 应答到达请求方,请求方最后确认,连接建立(第三次握手)
在经过三次握手后,就成功建立了TCP连接,任何采用TCP的应用在正式传输数据前都会先建立这条连接。
三次握手建立TCP连接也被称为同步。这个过程中双方交换的最重要参数就是初始序列号,初始序列号可以用来跟踪后续交换的每一个字节
建立TCP连接的双方没有主从之分,它们可以相互收发数据,也就是说TCP数据段的传输是全双工的
DoS攻击
三次握手连接可能导致一些安全问题,例如著名的:SYN泛洪导致DoS攻击
服务器通过大量的代理服务器,向被攻击的机器不断发送大量(泛洪)的第一次握手信息SYN,被攻击机器在收到第一次握手信息后会回发第二次握手信息,并且等待接收第三次握手信息,但是由于发送的第一次握手信息使用了伪造的IP地址,所以被攻击的机器永远无法收到第三次握手信息,这让被攻击者挂起很多进程在等待,最终因为资源耗尽而瘫痪
TCP连接释放
经过三次握手建立TCP连接之后,就可以开始进行数据的传输,在数据传输完后,就需要释放掉这条TCP连接
- 任何一方在没有数据要传送的时候,都可以发送一个FIN置位了的 TCP 数据段
- 当FIN被确认的时候,该方向的连接被关闭
- 当双向连接都关闭了的时候,连接释放
由于决定何时两边都释放这个问题具有一定难度,它极易形成两军队问题
两军队攻击敌人,单独出击必败,两军出击必胜,如何战胜敌人?最好的方法就是相互通信决定攻击时间,但一方发出消息后无法确定对方是否成功收到消息,因此对方会发出确认消息,由此双方会不断互发确认消息,无法结束,即最后信息的发送者,永远无法知道这个信息是否到达
为了避免两军队(two-army)问题,使用定时器:
如果一方发送了FIN数据段出去却在一个设定的时间没有收到应答,释放连接。另一方最终会注意到连接的对方已经不在了,超时后连接释放
理论上讲,如果初始DR的和重传都丢了,协议失败
发送者将放弃发送且释放连接,但是,另外一端却不知道这些情况,仍然处于活跃的状态,这种情形导致半开放连接(half-open)
杀死半开放连接的方式
- 如果在一定的时间内,没有TPDUs到达的话,连接自动释放
- 如果这样,传输实体在发送一个TPDU的时候必须启动定时
器,定时器超期,将发动一个哑TPDU(dummy TPDU),以免被断掉
三次握手正常释放连接
TCP四次挥手终止会话
最后的确认TPDU丢失
TCP传输策略
TCP传输采用了基本的肯定确认重传技术,TCP以数据段形式传输数据,一个数据段包含很多字节,相当于批量传输。为避免大量数据淹没接收方,采用流控技术。利用到了数据段当中的一个字段窗口尺寸(Window Size)。
可以看到整个流程中发送方首先向接收方传输了一个数据段,这个数据段大小2K,SEQ为0,表示从0开始填充字节
接收方大小为4K,此时接收方为空,接收方在成功接收数据段后剩余2K空余位置,然后向发送方回发确认,确认中包括了ACK=2048表示成功接收到了2048以前的字段,期望接受从2048往后的字段,以及WIN=2048表示接收方还剩余2K位空余位置,下次传输数据的大小不能超过2K
发送方在接收到确认后会继续发送剩余数据,可以看到,发送方在下次发送时,会根据确认调整传输数据大小以及初始序列号(SEQ)
在第二次传输数据完成后,接收方被占满,没有了空余位置,接收方收到确认后就会开始等待,等接收方重新获得空余位置并再次返回确认后再继续发送数据,知道所有数据全部传输完成
当窗口数为 0 时,发送者不能正常发送数据段,除非:
- Urgent数据。比如,用户想杀掉远端机器上的进程的时候,可以发送数据
- 发送者可以发送一个字节的数据段,以便让接收者再次发送期待接收的字节号和窗口数(避免死锁)
发送者不需要马上发送应用程序产生的数据,接收者也不需要马上发送应答(当收到数据的时候)
考虑一个指向某交互式编辑器(远程)的TELNET 连接,该编辑器对用户的每次击键都作出响应,在最坏的情况下:
- 当用户敲入一个字符的时候,被送到传输实体,创建一个21字节的数据段,在传到网络层,变成了41字节的IP分组
- 接收方(运行着编辑器的远端机)收到这个信息后,会立刻发送一个40字节的确认分组(20字节的TCP段头和20字节的IP头)
- 随后,当编辑器读取出这个字节,TCP实体发送一个窗口更新,这个分组也是40字节
- 最后,当编辑器处理了这个字符,它发送一个41字节的分组作为该字符的回显
- 总共累计起来,对于每个敲入的字符,需要至少 162 字节的带宽(还没有考虑到链路层的开销),发送4个数据段
优化接收端
接收端可以推迟500ms发送确认分组和窗口更新窗口,以便可以免费搭载在处理后的回显分组内(free ride)
优化发送端
Nagle算法
- 当数据以一次一字节的速度到达的时候,只发送第一个字节,然后将后续的字节缓存起来,直到发出的字节得到确认
- 将缓存起来的字节在一个数据段中发出,再继续缓存,直到发出的数据得到确认
Nagle算法在很多TCP上实现,但是有些时候最好禁用,比如:当一个X-Windows应用在互联网运行的时候,鼠标的移动事件必须发送给远程计算机,把这些移动事件收集起来一批一批发送出去,使得鼠标的移动极不连贯
傻瓜窗口综合症
另一个使TCP性能退化的问题是傻瓜窗口综合症(silly window syndrome problem):当有大块数据被传递给发送端TCP实体,但接收端的交互式应用每次只读取一个字节的时候,就会出现问题:
发送方每向接收方发送一个连接数据段,就会占满整个接收方的空间,然后接收方就会返回一个剩余大小为0的确认,导致发送方等待一段时间,直到新的确认返回后继续发送消息,但只要一发送数据段就会占满,导致数据无法从输入端传递到输出端。
解决方法
Clark解决方案 :阻止接收方发送只有1个字节的窗口更新,
相反,它必须等待一段时间,当有了一定数量的空间之后再
告诉发送方,接收方可以可以维护一个内部缓冲,且阻塞上层应用的READ 请求,直到它有大块的数据提供
总述:
发送方
- 尽量不发送数据含量小的数据段
- 缓存应用层的数据,达到一定量再发送
接收方
- 不请求对方发送短数据段(window size)
- 延迟窗口变更信息,使接收缓冲区足够大
TCP拥塞控制
虽然网络层也试图管理拥塞,但是,大多数繁重的任务是由
TCP来完成的,因为针对拥塞的真正解决方案是减慢数据率,所以TCP遵循分组守恒即当有一个老的分组离开之后才允许新的分组注入网络。 TCP希望通过动态维护窗口大小来实现这个目标
TCP拥塞检测(Congestion detection)
所有的互联网TCP算法都假定超时是由拥塞引起的,并且通过监视超时的情况来判断是否出现问题
拥塞控制 (Congestion prevention)
- 当一个连接建立的时候,双方选择一个合适的窗口大小,接收方根据自己的缓冲区大小来指定窗口的大小。
- 如果发送者遵守此窗口大小的限制,则接收端不会出现缓冲区溢出的问题,但可能由于网络内部的拥塞而发生问题(网络内部的瓶颈)
如图中(a)快速的网络向小容量的接收方传输数据(接收者容量问题),(b)慢速的网络向大容量的接受方传输数据(网络容量问题)
互联网解决方案应该是认识到两个潜在的问题的:网络容量,接收者容量,然后单独地处理这两个问题
为此,每个发送者维护两个窗口:
- 接收者窗口 大小反映了目前窗口的容量 (容易控制)
- 拥塞窗口 大小反映了网络目前的容量(难于控制)
为此要保证发送者发送的数据字节数是两个窗口中小的那个窗口数,这样就既不会因为接收者窗口大小导致拥塞,也不会因为网络容量大小导致拥塞
慢启动算法Slow Start
(决定拥塞窗口的大小)
- 当连接建立的时候,发送者用当前使用的最大数据段长度初始化拥塞窗口,然后发送一个最大的数据段
- 如果在定时器超期之前收到确认,则将拥塞窗口翻倍,然后发送两个数据段……直至超时(或达到接收方窗口的大小)
- 确定出拥塞窗口的大小
- 如:如果试图发送 4096字节没有问题,但是发送8192字节的时候,超时没有收到应答,则拥塞窗口设为4096个字节
因此在达到接收窗口大小或超时前,慢启动算法下的拥塞窗口大小都是以指数形式增长的
阈值
除了使用接收者窗口和拥塞窗口,TCP拥塞控制还是用了第三
个参数,阈值(threshold),初始化为64K
当一个超时发生的时候,阈值降为当前拥塞窗口的一半,同
时将拥塞窗口设为一个最大数据段的长度
使用慢启动算法来决定网络的容量,拥塞窗口增长到阈值时
停止指数增长
从这个点开始,每次成功的传输都会让拥塞窗口线性增长
(即每次仅增长一个最大的数据段长度)
注意:
- 线性增长,可以将越来越粗放的窗口尝试力度变小,以获得更准确的拥塞窗口值
- TCP慢启动算法就是这样不断超时,不断重启,尝试出的拥塞控制窗口值也随着网络状况的变化而变化,达到拥塞控制的目的
- 重新慢启动的时候,拥塞窗口值不用重置为一个数据段大小,而是可以设置为阈值大小,从这里直接开始线性增长,这就是所谓的快速恢复
- 如果收到一个ICMP抑制分组( ICMP source quench)并被送给TCP传输实体 ,则这个事件被当作超时对待
TCP定时器
重传定时器
TCP采用了肯定确认重传技术来保证每一个字节的可靠传输,为解决数据段丢失问题,每发一个数据段都会启动一个重传定时器,它是最重要的定时器之一
它的时间设置需要非常多的考量,如果时间设置过长,就会导致等待时间过长,如果设置过短,可能引发频繁的超时和重传
持续定时器
用来避免如下的死锁( deadlock )发生
死锁
- 接收方发送了一个窗口数为零的确认(窗口更新),告诉发送方等待。
- 稍后,接收方空出了缓冲,发送更新窗口的数据段,但是,很不幸,该分组中途丢失
- 现在,收发双方都在等待对方发送数据段过来,但永远等不到,死锁产生。
利用持续定时器解决死锁问题
当接收方发送一个窗口数为0的确认后,发送方开始启动一个持续定时器
此时,如果接收方在计时器限定时间范围内空出空间,并成功发送新确认到发送方,持续计时器结束并继续数据传输
假设持续计时器时间为0新的确认还没有到达,此时发送方就会发送一个探测数据段,里边没有任何数据内容,单纯引发接收方重新发送一个确认,以解决死锁问题
保活定时器
用来检查连接是否存活,当一个连接空闲的时间超过保活定时器的时间,该连接将被杀掉。
还有在关闭时刻处于TIMED WAIT状态中使用的定时器:运行两倍的最大分组生存时间,以确保连接关闭之后,该连接上的所有分组都完全消失。
性能 | TCP | UDP |
---|---|---|
可靠性 | T | F |
传输延迟 | 不确定 | 网络延迟 |
拥塞控制 | T | F |
TCP
- 可靠传输方式
- 可让应用程序简单化,程序员可以不必进行错误检查、修正等工作
UDP
- 为了降低对计算机资源的需求(DNS)
- 应用程序本身已提供数据完整性的检查机制,勿须依赖传输层的协议来保证
- 应用程序传输的并非关键性的数据(路由器周期性的路由信息交换)
- 一对多方式,必须使用UDP(TCP限于一对一的传送)(视频传播)