运输层协议
在不同主机的应用进程之间提供了逻辑通信,通过逻辑通信,运行不同进程的主机就会好像直接相连一样。
而网络层提供了主机之间的逻辑联系。
发送端: 运输层把应用程序进程接收到的报文转换成运输层分组,成为运输层报文段。实现方法为把应用报文划分为较小的块,并为每块加上一个运输层首部以生成运输层报文段。在发送端系统当中,运输层把这些报文段传递给网络层,网络层将其封装为网络层分组,向目的地发送。
网络路由器仅仅作用于数据报的网络层字段,即不检查封装在该数据报的运输层报文段的字段。
接收端:网络层提取运输层报文段,把报文段上交给运输层,运输层处理接收到的报文段,使得该报文段中的数据为接收应用进程使用。
网络层提供了主机之间的逻辑通信,而运输层为运行在不同主机上的进程提供了逻辑通信。
运输协议能够提供的服务常常受制于网络层协议的服务模型。如果网络层协议无法为主机之间发送的运输层报文段提供时延或者带宽保证的话,运输层也不能为进程之间的发送应用程序报文提供时延或者带宽保证
名词解释
UDP: 用户数据报协议:不可靠,无连接
TCP: 传输控制协议: 可靠,面向连接
运输层分组:报文段
IP:网络层的一个协议,每台主机一个IP地址,是不可靠服务
IP服务类型是尽力而为,不可靠的。
带宽: 数据通信的最大吞吐量
报文段: TCP和UDP的分组
数据报: 网络层分组
多路复用与多路分解
TCP 和 UDP 最基本责任: 把两个端系统间的IP的交付服务拓展为运行在端系统上的两个进程之间的交付服务。
这个过程也叫作多路复用和多路分解
运输层从下方的网络层接收报文段,运输层负责把这些报文段中的数据交付给主机上运行的应用程序进程。
一个进程有一个或多个套接字,socket作为进程与网络传递数据的一个门户。
那么怎么把运输层报文段定向到适当的套接字?接收端中,运输层检查这些字段,标识出接收套接字,进而把报文段定向到该套接字。
1 | 将运输层报文段中的数据交付到正确的套接字叫做多路分解 |
运输层报文段中的源与目的端口字段
1.套接字有唯一标识符
2.每个报文段有特殊字段来指示该报文段所要交付到的套接字。
在主机上的每个套接字能够分配一个端口号,当报文段到达主机时,运输层检查报文段中的目的端口号,并且将其定向到相应的套接字。然后报文段中的数据通过套接字进入其所连接的进程。
校检和校验的范围:伪头部,UDP头部以及数据 伪头部用于检查UDP用户数据报是否正确到达了指定主机(目的IP地址)的指定端口号
无连接的多路复用与分解
无连接是指发送方和接收方的运输层实体之间没有握手。
UDP是通过(目的IP,目的端口号)来标识的。如果源IP和源端口号相同,那么会两个报文段会通过相同的套接字被定向到相同的目的进程。
例子:
主机A一个进程有UDP端口19157,他要发送一个应用程序数据块给位于主机B的另一个进程,该进程具有UDP端口46428,主机A的运输层创建一个运输层报文段,其中包括应用程序数据,源端口号以及目的端口号。
运输层把报文段传递给网络层封装到一个IP数据报,然后交付给主机B。B能够运行多个进程,每个进程有自己的UDP套接字与相应的端口号。B会检查报文段的目的端口号,将每个报文段定向分解到相应的socket
而源端口号的用途就是可以作为B回发报文给A的时候,作为返回地址的一部分。
连接的多路复用与分解
TCP套接字由一个四元组(源IP地址,源端口号,目的IP地址,目的端口号)来标志。而UDP标识的二元组仅有目的IP地址和目的端口号。
当TCP报文段从网络到达一台主机的时候,主机使用全部四个数值来把报文段定向分解到相应的套接字。
具体来说,对UDP,如果两个报文段的有不同的源IP地址和源端口号,但具有相同的目的IP地址和目的端口号,那么两个报文段将通过相同的目的套接字被定向到相同的目的进程。
而TCP如果两个报文段的源IP地址和端口号不同,会被定向到两个不同的套接字。
例子:
1.TCP服务器有一个 socket 它在12000端口上等待来自TCP客户的连接请求。
2.客户创建一个套接字,发起连接请求。
1 |
|
3.
1 | connectionSoekct,addr = serverSoskct.accept() |
操作系统接收到具有目的端口的连接请求报文段,该服务器进程在端口12000等待接受连接,并且创建一个新的套接字。
持续HTTP连接的使用:整条持续链接期间,客户与服务器之间经由同一个服务器套接字交换HTTP报文,然而如果使用非持续HTTP链接,每一对请求/响应都创建一个新的TCP链接然后随之关闭。
无连接运输 UDP
在发送报文段之前,发送方和接收方的运输层实体之间没有握手。直接与IP打交道,UDP从应用程序得到数据,附加上用于多路复用和分解的源端口和源地址以及其他两个小字段,然后把形成的报文段交给网络层。网络层把运输层报文段封装到一个IP数据报中,然后尽力把报文段交付给接收主机。主机接收到报文段之后UDP使用目的端口把报文段中的数据交付给正确的应用程序。
UDP利用
面向连接的TCP
应用进程开始向另外一个进程发送数据之前,两个进程必须先相互握手。即必须相互发送某些预备报文段,以确定数据传输的参数。
TCP链接提供的是全双工服务,如果两个进程之间存在TCP链接,那么应用层数据可以在进程B和进程A之间相互流动。
TCP链接点对点,是单个发送方与单个接收方之间的连接。
面向连接:进行数据传输的时候首先要建立一条传输链接,相互发送某些预备的报文,链接双方要建立确保数据传输所需要的参数,传输完成之后要把链接释放掉。
TCP三次握手https://wenku.baidu.com/view/f0256510b207e87101f69e3143323968011cf40b.html?rec_flag=default
TCP会为每块客户数据配上一个TCP首部,从而形成多个TCP报文段,报文段被下传到网络层,网络层将其封装在网络层IP数据报中,然后再被发送到网络。
目的是防止报文段在传输链接建立过程中出现差错,也保证发送方和接收方发送和接收数据能力没有差错。
构造可靠数据传输协议
解决流水线的差错恢复两种基本方法:
1.回退N步(GBN)
发送方在发完一个数据帧之后,连续发送若干个数据帧,即使在连续发送的过程中收到了接收方发来的应答帧,也可以继续发送。发送方在发完一个数据帧的时候都要设置超时定时器,当发送了N个帧之后,如果发现该N帧的前一个帧在计时器超时后仍未返回确认信息,则判断该帧出错或者丢失,发送方不得不重新发送出错帧以及其后的N帧。
“累计确认”:允许接收端在连续收到好几个正确的确认帧之后,只对最后一个数据帧发送确认信息。
2.选择重传(SR)
通过让发送方仅重传那些它怀疑在接收方出错的分组而避免了不必要的重传。
就是接收方发现某帧出错之后,其后继续送来的正确的帧虽然不能立即递交给接收方的高层,但接收方可以收下来,存放在一个缓冲区中。
同时要求发送方重新传送出错的那一帧,一旦收到重新传来的那个帧,就可以要把缓存区的其他帧一起按正确的顺序传递给高层。
TCP报文结构
数据偏移:TCP的首部长度,以32bit为单位
窗口大小16bit,用来指示接收方滑动窗口的大小,用于实现TCP的流量控制。
校检和 实现对TCP数据的校检,所有16位字节计算反码和,然后取反
红字解答: 900 - 1000 序号对应的数据将会存储在缓存当中,当536-899重传之后,会按序发送给应用,确保按需到达。
报文段序号是第一个数据字节的字节流编号,确认号(ACK)是希望从对方接收到的数据的下一个字节的编号。
可靠数据传输
确保进程从接收缓存读出的数据流是非损坏的,连续的,非冗余的,按序的字节流。
TCP sender simulator
1 |
|
重传定时器
1.定时器只与最早的未被确认的报文段关联起来。
2.采用自适应的重传计时策略
往返时间的估算
对于每一条TCP链接,维护一个变量EstimatedRTT,存放所估计的源到目的端的往返传输时间。
如果定时器过期之前数据段被确认,则记录下该次TCP报文段的往返传输时间SampleRTT
SampleRTT会变化,会使用若干最新的测量结果。
具体使用指数加权移动平均
重传超时间隔
TCP重传超时间隔:加倍时间间隔
TCP报文段超时并重传:对于重传报文段不更新RTT,把超时间隔加倍。
快速重传
如果TCP发送方收到对同一数据的3个冗余ACK,就认为发生了丢包(2个的话可能是乱序到达引起的)
GBN 和 SR
GBN
累计确认:正确接收到但是失序的报文段不会被接收方逐个确认。
定时器只与最早的未确认报文段关联起来
代码看我github
SR
超时发生的时候,只重传超时的一个报文段。
TCP会把很多正确接收但失序的报文段缓存起来。
TCP流量控制
TCP为应用程序提供了流量控制服务,用来消除发送方使得接收方缓存溢出的可能性。
TCP让发送方维护一个接收窗口的变量来提供流量控制,这个窗口用来给发送方指示接收方还有多少可用的缓存空间。
TCP———双工: 各自都维护一个接收窗口。
LastByteRead:主机B中的应用进程从缓存中读出的数据流的最后一个字节的编号。
LastByteRevd:从网络中到达的并且已经放入主机B接收缓存中的数据流的最后一个字节的编号。
TCP不允许已分配的缓存溢出:
1 |
|
接收窗口用rwnd表示,根据缓存可用空间的数量来设置。
1 |
|
具体实现
1.主机B把当前rwnd值放到发送给主机A的报文段中接收窗口字段中,用来通知主机A它在该连接的缓存中还有多少可用空间。
2.开始的时候主机B设定rwnd = RevBuffer ,主机A要保证
1 | LastByteSent - LastByteAcked <= rwnd |
特殊情况讨论:
当主机B接收窗口为0的时候,主机A继续发送一个只有一个字节数据的报文段。这些报文段会被接收方确认,最终缓存将开始清空。并且确认报文中将包含一个非0的值。
这也就是(probe),防止死锁
糊涂窗口综合征
1 | 当发送端应用进程产生数据很慢、或接收端应用进程处理接收缓冲区数据很慢,或二者兼而有之;就会使应用进程间传送的报文段很小,特别是有效载荷很小。极端情况下,有效载荷可能只有1个字节;而传输开销有40字节(20字节的IP头+20字节的TCP头) 这种现象就叫糊涂窗口综合症。 |
发送端引起的:
如果发送端为产生数据很慢的应用程序服务(典型的有telnet应用),例如,一次产生一个字节。这个应用程序一次将一个字节的数据写入发送端的TCP的缓存。如果发送端的TCP没有特定的指令,它就产生只包括一个字节数据的报文段。结果有很多41字节的IP数据报就在互连网中传来传去。解决的方法是防止发送端的TCP逐个字节地发送数据。必须强迫发送端的TCP收集数据,然后用一个更大的数据块来发送。发送端的TCP要等待多长时间呢?如果它等待过长,它就会使整个的过程产生较长的时延。如果它的等待时间不够长,它就可能发送较小的报文段,于是,Nagle找到了一个很好的解决方法,发明了Nagle算法。而他选择的等待时间是一个RTT,即下个ACK来到时。
接收端引起的:
接收端的TCP可能产生糊涂窗口综合症,如果它为消耗数据很慢的应用程序服务,例如,一次消耗一个字节。假定发送应用程序产生了1000字节的数据块,但接收应用程序每次只吸收1字节的数据。再假定接收端的TCP的输入缓存为4000字节。发送端先发送第一个4000字节的数据。接收端将它存储在其缓存中。现在缓存满了。它通知窗口大小为零,这表示发送端必须停止发送数据。接收应用程序从接收端的TCP的输入缓存中读取第一个字节的数据。在入缓存中现在有了1字节的空间。接收端的TCP宣布其窗口大小为1字节,这表示正渴望等待发送数据的发送端的TCP会把这个宣布当作一个好消息,并发送只包括一个字节数据的报文段。这样的过程一直继续下去。一个字节的数据被消耗掉,然后发送只包含一个字节数据的报文段。
解决方法:
接收方:
1.仅当窗口大小显著增加之后才发送增加窗口的通告。显著增加意味着窗口大小到达缓冲区空间的一半或者一个MSS的时候。———— 推迟确认技术
2.推迟确认的缺点是当确认延迟太大的时候,会导致不必要的重传,给TCP估计往返时间带来混乱。
发送方:
为了防止发送短的报文段,在发送报文段之前延迟,直到聚集足够多的数据量。采用Nagle算法来决定延迟的时间。
Nagle 算法
为了尽可能发送大块数据,避免网络中充斥着小数据块。任意时刻最多只能有一个未被确认的小段。
1 | if data is available && window != MSS{ |
TCP 连接管理
三次握手:
三次握手原因:
发送方要知道自己有没有发出去,对方有没有接收到。第三次握手是为了让服务端知道自己的发送能力是没问题的。
第一次握手:客户端发送能力验证
第二次握手:服务端的接受能力与客户端的接受能力验证
第三次握手:服务端的发送能力验证(要求确认第二次握手发送成功了,问问客户端有没有成功)
另外一原因是防止已经失效的链接重传到服务器端。
当客户A发送连接请求,但因连接请求报文丢失而未收到确认。于是A会再次重传一次连接请求,此时服务器端B收到再次重传的连接请求,建立了连接,然后进行数据传输,数据传输完了后,就释放了此连接。假设A第一次发送的连接请求并没有丢失,而是在网络结点中滞留了太长时间,以致在AB通信完后,才到达B。此时这个连接请求其实已经是被A认为丢失的了。如果不进行第三次握手,那么服务器B可能在收到这个已失效的连接请求后,进行确认,然后单方面进入ESTABLISHED状态,而A此时并不会对B的确认进行理睬,这样就白白的浪费了服务器的资源。如果进行了第三次握手,那么A不会向B发送确认,那个重传的连接请求就会失效。
释放连接
释放连接可以看成四次挥手,当然FIN与ACK合并可以看成三次。
洪泛攻击
好的参考网址
http://www.52im.net/thread-515-1-1.html
拥塞控制
TCP拥塞控制原理
发送方如何限制它向其连接发送流量的速率?
TCP链接可以维护一个拥塞窗口变量,其反映了网络的容量,限制发送方向网络注入数据的速度必须小于接受窗口和拥塞窗口中的最小值。
1 |
|
发送方如何感知其到目的地之间的路径上存在拥塞?
拥塞的时候路由器的缓存器溢出,导致报文段丢弃,引起发送方的丢失。
路径上出现拥塞。
TCP发送方发生”丢失”
1.超时
2.连续收到3个冗余的ACK
自计时 self-clocking
使用对以前未确认的报文段的确认来触发拥塞窗口congestionWindow长度的增加
慢启动
拥塞避免(加性增)
1.每个RTT窗口只能增加一个MSS
2.rtt动态变化,TCP实现中通常采用
1 | congwindow = congwindow + MSS*(MSS/congwindow) |
是一个线性上升的算法
出现拥塞
1.TCP TAHOE (乘性减)
TCP超时或者收到3个冗余的ACK的时候,需要重传
ssthresh缩减为拥塞窗口一半,并且拥塞窗口恢复到原来初始窗口大小,进入slow start process
1 | ssthresh = max(congWindow/2,MSS) |
然后进入下面的快速恢复算法
快速回复,取消慢启动
TCP reno:
在进入Fast recovery 之前,cwnd与sshthresh会被更新:
cwnd = cwnd / 2
sshthresh= cwnd
进入快速恢复算法
真正的Fast recovery 算法如下:
维护ssthresh变量
1.拥塞窗口小于阈值时候进入慢启动阶段
2.大于该阈值的时候进入拥塞避免阶段
拥塞避免的总结
1.慢启动和拥塞避免
慢启动:拥塞窗口小于阈值ssthresh的时候指数增加
拥塞避免:拥塞窗口大于阈值的时候进入拥塞避免阶段(加性增)
超时(丢失)的时候乘性减:每次超时,把threshold设置为当前拥塞窗口的一半,并重新回到慢启动阶段
慢启动是每次收到一个ACK就增加一个MSS,然而拥塞避免是每一个RTT增加一个MSS
当检测到超时而丢包的时候,进入tahoe的慢启动
TCP出现拥塞:(tahoe)
ssthresh = max(congwindow/2,MSS)
congwindow = MSS(即初始窗口的大小)
TCP出现拥塞:(Reno)(快速恢复)
与tahoe不同的是,他是进入拥塞避免阶段
ssthresh = max(CongWindow/2,MSS)
CongWindow = ssthresh (设置为阈值)
当检测到3个冗余的ACK的丢包的时候,进入快速恢复状态,
ssthresh = CongWindow /2 , CongWindow = ssthresh+(3×MSS)
如果收到冗余的ACK CongWindow+=MSS
超时前收到新的ACK,直接进入拥塞避免阶段
总结
1.慢启动 CongWindow < ssthresh 窗口指数级增长
2.拥塞避免 CongWindow > ssthresh 线性增长
3.收到3个冗余ACK而检测到丢包:
ssthresh = CongWindow / 2
CongWindow = ssthresh + (3*MSS)
每收到一个冗余的ACK,CongWindow +=Mss
超时前收到新的Ack,会直接进入拥塞避免阶段。
4.
超时事件发生丢包的时候,ssthresh = CongWindow/2
CongWindow = 1 MSS
UDP和TCP总结
UDP 优点:
1.协议简单,运行效率高
2.首部开销小,8个字节
3.支持一对一,多对多,一对多的交互通信
缺点:
不可靠,容易发生丢包
应用:
追求速度,例如聊天工具,实时视频聊天
TCP优点:
提供可靠的服务,TCP传送的数据无差错,不丢失,不重复而且按序到达
缺点:
首部开销大,20个字节
会出现网络用塞,使得源主机发送效率降低。
协议复杂,速度慢