TCP/IP
数据在网络中传输最终一定是通过物理介质传输。物理介质就是把电脑连接起来的物理手段,常见的有光纤、双绞线,以及无线电波,它决定了电信号(0和1)的传输方式,物理介质的不同决定了电信号的传输带宽、速率、传输距离以及抗干扰性等等。网络数据传输就像快递邮寄,数据就是快件。只有路打通了,你的”快递”才能送到,因此物理介质是网络通信的基石。
寄快递首先得称重、确认体积(确认数据大小),贵重物品还得层层包裹填充物确保安全,封装,然后填写发件地址(源主机地址)和收件地址(目标主机地址),确认快递方式。对于偏远地区,快递不能直达,还需要中途转发。网络通信也是一样的道理,只不过把这些步骤都规定成了各种协议。
TCP/IP的模型的每一层都需要下一层所提供的协议来完成自己的目的。我们来看下数据是怎么通过TCP/IP协议模型从一台主机发送到另一台主机的。
当用户通过HTTP协议发起一个请求,应用层、传输层、网络互联层和网络访问层的相关协议依次对该请求进行包装并携带对应的首部,最终在网络访问层生成以太网数据包,以太网数据包通过物理介质传输给对方主机,对方接收到数据包以后,然后再一层一层采用对应的协议进行拆包,最后把应用层数据交给应用程序处理。
TCP/IP 与 HTTP
TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP 协议不仅仅指的是 TCP 和 IP 两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。
而HTTP是应用层协议,主要解决如何包装数据。
“IP”代表网际协议,TCP 和 UDP 使用该协议从一个网络传送数据包到另一个网络。把IP想像成一种高速公路,它允许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的“卡车”,它们携带的货物就是像HTTP,文件传输协议FTP这样的协议等。
TCP | UDP | |
---|---|---|
连接性 | 面向连接 | 面向非连接 |
传输可靠性 | 可靠 | 不可靠 |
报文 | 面向字节流 | 面向报文 |
效率 | 传输效率低 | 传输效率高 |
流量控制 | 滑动窗口 | 无 |
拥塞控制 | 慢开始、拥塞避免、快重传、快恢复 | 无 |
传输速度 | 慢 | 快 |
应用场合 | 对效率要求低,对准确性要求高或要求有连接的场景 | 对效率要求高,对准确性要求低 |
TCP和UDP协议的一些应用。
UDP
UDP分组叫做用户数据报,有八个字节的固定首部。
源端口号
源主机上运行的进程所使用的端口号。16位长。
- 若源主机是客户,大多数情况这个端口号是该进程请求的一个临时端口号。
- 若源主机是服务器,则大多数情况下这个端口号是一个熟知端口号。
目的端口号
目的主机上运行的进程所使用的端口号。16位长。
- 若目的主机是服务器,则大多数情况下这个端口号是熟知端口号。
- 若目的主机是客户端,则大多数情况下是一个临时端口号。
总长度
定义了用户数据报的总长度,首部加上数据。16位可定义的总长度是从0-65535字节。
UDP提供无连接的服务,UDP发送的每一个数据报都是一个独立的数据报,不同的用户数据报之间没有任何联系,哪怕是来自相同的源进程并且去往相同的目的程序。用户数据报没有编号,每一个用户数据报可以走不同的路径。
无连接导致的结果就是:使用UDP的进程不能发送数据流到UDP,也不能期望UDP把这个数据流分割称为许多个相互关联的用户数据报。相反,进程的每一个请求都必须足够小,使其能够装入一个用户数据报中。
UDP没有流量控制、差错控制和拥塞控制。
UDP检验和检验伪首部、UDP首部和应用层来的数据。伪首部是封装在用户数据报的那个IP分组的首部的一部分。
要把报文从一个进程发送到另一个进程,UDP协议就要对报文进行封装和解封。
当一个进程启动时,会创建一个入队列和出队列。客户端的时候,进程终止,队列销毁,服务器时,队列始终打开。进程使用源端口号将报文送到出队列,UDP逐个把报文取出,先添加首部,再交付给IP。若发生溢出,则要求客户进程先等待,稍后发送。
当报文到达客户端或服务器进程时,检查目的端口号中的队列是否创建,没有则丢弃并请求ICMP协议发送端口不可达报文。报文不管是来自相同或者不同的进程,都被放入同一个队列。
主机上只有一个UDP,但多个进程要使用UDP服务,所以UDP可以进行复用和分用。
复用:UDP接收来自不同的进程的报文,这些进程通过指派给它们的端口号来区分。添加首部后,将用户数据报送往IP。
分用:UDP接收来自IP的用户数据报。经过差错检查并剥除首部后,UDP根据端口号把每一个报文交付到适当的进程。
UDP的主要特点
- UDP是无连接的
- 尽最大努力交付
- 面向报文。对应用层交付下来的报文既不合并也不拆分。一次交付完整的报文。应用程序必须选择合适大小的报文。
- 没有流量控制、差错控制和拥塞控制。
- 支持一对一、一对多、多对一和多对多的交互通信。
- 首部开销小,只有8个字节。
TCP
TCP连接的建立与终止
TCP虽然是面向字节流的,但TCP传送的数据单元却是报文段。一个TCP报文段分为首部和数据两部分,而TCP的全部功能体现在它首部中的各字段的作用。
TCP报文段首部的前20个字节是固定的(下图),后面有4n字节是根据需要而增加的选项(n是整数)。因此TCP首部的最小长度是20字节。
TCP报文首部
-
源端口和目的端口,各占2个字节,分别写入源端口和目的端口;
-
序列号(Sequence number),占4字节。序号范围是【0,2^32 - 1】,共2^32个序号。序号增加到 2^32-1后,下一个序号就又回到 0。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则是指的是本报文段所发送的数据的第一个字节的序号。例如,一报文段的序号是301,而接待的数据共有100字节。这就表明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值应为401。这个字段的序号也叫“报文段序号”;
-
确认号(Acknowledge number),占4个字节,是期望收到对方下一个报文的第一个数据字节的序号。例如,B收到了A发送过来的报文,其序列号字段是501,而数据长度是200字节,这表明B正确的收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701;
-
数据偏移,占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。
-
保留,占6位,保留为今后使用,但目前应置为0;
-
紧急URG(URGent),当URG=1,表明紧急指针字段有效。告诉系统此报文段中有紧急数据;
-
确认ACK(ACKnowledgment),仅当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有报文的传输都必须把ACK置1;
-
推送PSH(PuSH) ,当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应,这时候就将PSH=1;
-
复位RST(ReSeT),当RST=1,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立连接;
-
同步SYN(SYNchronization),在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1;
-
终止FIN(FINis),用来释放连接。
当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放;
-
窗口,占2字节,指的是通知接收方,发送本报文你需要有多大的空间来接受;
-
检验和,占2字节,校验首部和数据这两部分;
-
紧急指针,占2字节,指出本报文段中的紧急数据的字节数;
-
选项,长度可变,定义一些其他的可选的参数
TCP是一种面向连接的单播协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务器的内存里保存的一份关于对方的信息,如ip地址、端口号等。
TCP 三次握手
所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。
-
第一次握手(SYN=1, seq=x)
建立连接。客户端发送连接请求报文段,这是报文首部中的同步位SYN=1,同时选择一个初始序列号 seq=x ,此时,客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号;
-
第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1)
服务器收到客户端的SYN报文段,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号ACKnum=x+1,同时,自己还要发送SYN请求信息,SYN=1,为自己初始化一个序列号 seq=y,服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。
-
第三次握手(ACK=1,ACKnum=y+1)
客户端收到服务器的SYN+ACK报文段,再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,确认号 ACKnum = y+1,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED(已建立连接)状态,完成TCP三次握手。
为什么要采用三次握手二而不是两次呢?
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
具体例子:“已失效的连接请求报文段”的产生在这样一种情况下:client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 server。本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后,就误认为是 client 再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
讲一讲SYN超时,洪泛攻击,以及解决策略
什么 SYN 是洪泛攻击? 在 TCP 的三次握手机制的第一步中,客户端会向服务器发送 SYN 报文段。服务器接收到 SYN 报文段后会为该 TCP 分配缓存和变量,如果攻击分子大量地往服务器发送 SYN 报文段,服务器的连接资源终将被耗尽,导致内存溢出无法继续服务。
解决策略: 当服务器接受到 SYN 报文段时,不直接为该 TCP 分配资源,而只是打开一个半开的套接字。接着会使用 SYN 报文段的源 Id,目的 Id,端口号以及只有服务器自己知道的一个秘密函数生成一个 cookie,并把 cookie 作为序列号响应给客户端。
如果客户端是正常建立连接,将会返回一个确认字段为 cookie + 1 的报文段。接下来服务器会根据确认报文的源Id,目的 Id,端口号以及秘密函数计算出一个结果,如果结果的值 +1等于确认字段的值,则证明是刚刚请求连接的客户端,这时候才为该 TCP 分配资源
这样一来就不会为恶意攻击的 SYN 报文段分配资源空间,避免了攻击。
粘包问题
产生粘包问题的原因有以下几个:
- 第一 ,应用层调用write方法,将应用层的缓冲区中的数据拷贝到套接字的发送缓冲区。而发送缓冲区有一个SO_SNDBUF的限制,如果应用层的缓冲区数据大小大于套接字发送缓冲区的大小,则数据需要进行多次的发送。
- 第二种情况是,TCP所传输的报文段有MSS的限制,如果套接字缓冲区的大小大于MSS,也会导致消息的分割发送。
- 第三种情况由于链路层最大发送单元MTU,在IP层会进行数据的分片。
这些情况都会导致一个完整的应用层数据被分割成多次发送,导致接收对等方不是按完整数据包的方式来接收数据。
粘包的问题的解决思路
粘包问题的最本质原因在与接收对等方无法分辨消息与消息之间的边界在哪。我们通过使用某种方案给出边界,例如:
- 发送定长包。如果每个消息的大小都是一样的,那么在接收对等方只要累计接收数据,直到数据等于一个定长的数值就将它作为一个消息。
- 包尾加上\r\n标记。FTP协议正是这么做的。但问题在于如果数据正文中也含有\r\n,则会误判为消息的边界。
- 包头加上包体长度。包头是定长的4个字节,说明了包体的长度。接收对等方先接收包体长度,依据包体长度来接收包体。
- 使用更加复杂的应用层协议。
TCP 四次挥手
TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作。
-
第一次挥手(FIN=1,seq=x)
主机1(可以使客户端,也可以是服务器端),设置seq=x,向主机2发送一个FIN报文段;此时,主机1进入**
FIN_WAIT_1
状态**;这表示主机1没有数据要发送给主机2了; -
第二次挥手(ACK=1,ACKnum=x+1)
主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknnum=x+1,主机1进入**
FIN_WAIT_2
状态**;主机2告诉主机1,我“同意”你的关闭请求; -
第三次挥手(FIN=1,seq=y)
主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入**
LAST_ACK
状态** -
第四次挥手(ACK=1,ACKnum=y+1)
主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入**
TIME_WAIT
状态**;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了,进入CLOSED
状态。主机 1 等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入
CLOSED
状态。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是**关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。**故需要四步握手。
由于 TCP 协议是全双工的,也就是说客户端和服务端都可以发起断开连接。两边各发起一次断开连接的申请,加上各自的两次确认,看起来就像执行了四次挥手。
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
2*MSL(maximum segment lifetime),可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout
查看MSL的值
第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器
第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
如果已经建立了连接, 但是客户端突发故障了怎么办?
TCP设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
服务器出现了大量CLOSE_WAIT状态如何解决
大量 CLOSE_WAIT 表示程序出现了问题,对方的 socket 已经关闭连接,而我方忙于读或写没有及时关闭连接,需要检查代码,特别是释放资源的代码,或者是处理请求的线程配置。
TCP协议如何来保证传输的可靠性
对于可靠性,TCP通过以下方式进行保证:
- 数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时TCP发送数据端超时后会重发数据;
- 对失序数据包重排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。TCP将对失序数据进行重新排序,然后才交给应用层;
- 丢弃重复数据:对于重复数据,能够丢弃重复数据;
- 应答机制:当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒;
- 超时重发:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;
- 流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP使用的流量控制协议是可变大小的滑动窗口协议。
超时重传机制
主机A发送数据给B之后, 可能因为网络拥堵等原因, 数据无法到达主机B如果主机A在一个特定时间间隔内没有收到B发来的确认应答, 就会进行重发但是主机A没收到确认应答也可能是ACK丢失了。这种情况下, 主机B会收到很多重复数据, 那么TCP协议需要识别出哪些包是重复的,并且把重复的丢弃。这时候利用前面提到的序列号, 就可以很容易做到去重。
超时时间如何确定? 最理想的情况下, 找到一个最小的时间, 保证 “确认应答一定能在这个时间内返回”.但是这个时间的长短, 随着网络环境的不同, 是有差异的.如果超时时间设的太长, 会影响整体的重传效率; 如果超时时间设的太短, 有可能会频繁发送重复的包.
TCP为了保证任何环境下都能保持较高性能的通信, 因此会动态计算这个最大超时时间.
- Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍.如果重发一次之后, 仍然得不到应答, 等待 2500ms 后再进行重传. 如果仍然得不到应答, 等待 4500ms 进行重传.依次类推, 以指数形式递增. 累计到一定的重传次数, TCP认为网络异常或者对端主机出现异常, 强制关闭连接.
滑动窗口机制
如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。
利用滑动窗口机制可以很方便地在TCP连接上实现对发送方的流量控制。
从上面的图可以看到滑动窗口左边的是已发送并且被确认的分组,滑动窗口右边是还没有轮到的分组。滑动窗口里面也分为两块,一块是已经发送但是未被确认的分组,另一块是窗口内等待发送的分组。随着已发送的分组不断被确认,窗口内等待发送的分组也会不断被发送。整个窗口就会往右移动,让还没轮到的分组进入窗口内。
可以看到滑动窗口起到了一个限流的作用,也就是说当前滑动窗口的大小决定了当前 TCP 发送包的速率,而滑动窗口的大小取决于拥塞控制窗口和流量控制窗口的两者间的最小值。
流量控制
TCP 是全双工的,客户端和服务器均可作为发送方或接收方,我们现在假设一个发送方向接收方发送数据的场景来讲解流量控制。首先我们的接收方有一块接收缓存,当数据来到时会先把数据放到缓存中,上层应用等缓存中有数据时就会到缓存中取数据。假如发送方没有限制地不断地向接收方发送数据,接收方的应用程序又没有及时把接收缓存中的数据读走,就会出现缓存溢出,数据丢失的现象,为了解决这个问题,我们引入流量控制窗口。
假设应用程序最后读走的数据序号是 lastByteRead,接收缓存中接收到的最后一个数据序号是 lastByteRcv,接收缓存的大小为 RcvSize,那么必须要满足 lastByteRcv - lastByteRead <= RcvSize
才能保证接收缓存不会溢出,所以我们定义流量窗口为接收缓存剩余的空间,也就是 Rcv = RcvSize - (lastByteRcv - lastByteRead)
。只要接收方在响应 ACK 的时候把这个窗口的值带给发送方,发送方就能知道接收方的接收缓存还有多大的空间,进而设置滑动窗口的大小。
如果接收到rwnd=0的报文段,表示接收端暂时关闭窗口。发送方暂停发送数据,直到收到一个新通告。如果后来发送的新通告丢失,则可能产生死锁。所以,为了防止死锁,TCP为每一个连接设置一个持续计时器,只要TCP连接的一方收到对方的零窗口通知,就启动该计时器。若持续计时器到期,就发送一个零窗口探测报文段(仅携带一字节的数据),而对方就在这个探测报文段时给出了现在的窗口值。若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器。若窗口不是零,则死锁的僵局就可以打破了。
拥塞控制
拥塞控制是指发送方先设置一个小的窗口值作为发送速率,当成功发包并接收到 ACK 时,便以指数速率增大发送窗口的大小,直到遇到丢包(超时/三个冗余ACK),才停止并调整窗口的大小。这么做能最大限度地利用带宽,又不至于让网络环境变得太过拥挤。
最终滑动窗口的值将设置为流量控制窗口和拥塞控制窗口中的较小值。
发送方的窗口 = MIN(cwnd,rwnd),cwnd拥塞窗口大小,rwnd接收窗口大小。
TCP的拥塞处理
计算机网络中的带宽、交换结点中的缓存及处理机等都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就会变坏,这种情况就叫做拥塞。拥塞控制就是防止过多的数据注入网络中,这样可以使网络中的路由器或链路不致过载。注意,拥塞控制和流量控制不同,前者是一个全局性的过程,而后者指点对点通信量的控制。拥塞控制的方法主要有以下四种:
- 慢启动:不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小;
- 拥塞避免:拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加1,而不是加倍,这样拥塞窗口按线性规律缓慢增长。
- 快重传:快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
- 快恢复:快重传配合使用的还有快恢复算法,当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh 门限减半,但是接下去并不执行慢开始算法:因为如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将 cwnd 设置为ssthresh 的大小,然后执行拥塞避免算法。
慢开始:指数增大
每当有1个报文段被确认,拥塞窗口就增大1个MSS。
慢开始算法中,拥塞窗口大小按指数规律增长,直至达到门限为止。
拥塞避免:加法增大
当拥塞窗口大小达到慢开始的门限时,慢开始阶段就停止,而加法增加阶段就开始了。
在拥塞避免算法中,拥塞窗口的大小按照加法规律增长,直至检测到拥塞为止。
拥塞检测:乘法减小
当RTO计时器超时或当收到了三个重复的ACK(快重传、快恢复)时,门限值都下降到一半(乘法减小)。
IP协议
网络层
计算机网络的层次结构其实可以和现实生活中的快递系统进行类比,虽然不完全相同,却有着很多的相似点。物理层可以类比快递车、铁路、公路等这些实际传输介质和物理设施,这一层什么也不知道,只是机械的运输。数据链路层相当于快递员,他们有思想,会对包裹进行检测,进行打包,但也不知道包裹的细节,只是将一个个大同小异的快递盒运送到他负责的那些目的地,需要的也只是最后的小地址。而网络层则相当于一个个集散中心所组成的体系,集散中心需要快递前面的大地址,就是网络层的ip地址,需要在各个路由器转发,送到不同的网络,这里对快递的细节掌握的更多。
快递在运送大型货物的时候,会耗费大量人力物力,降低效率。同样在网络层进行报文交换时,如果报文较大,则一样会浪费很多资源,增加时延。所以像现实生活一样,将大报文分解成小的数据报(分组),一个个的传输,即分组交换方式,以此提高效率。那么问题又来了,这些“小包裹”是先联系好收件人协商特定的路线运输,来保证这些“包裹发送无误,有序到达。还是任意路线发,尽量保证你都收到?
所以网络层的分组交换又分为虚电路方式和数据报方式两种。虚电路是面向连接的,类似于电路交换,只不过建立的是逻辑连接而不是物理连接。数据报则是面向无连接的。
虚电路方式
网络层采用虚电路服务时:
- 报文发送前需要先建立一条虚连接(逻辑连接)以指定这些数据报通过的路径,然后传输数据,最后断开连接。
- 分组不仅包含源地址和目的地址,还包含一个流标号(即虚电路标识符),用来指定这些数据报通过的路径。
- 所传送的分组按序到达。
虚电路服务提供可靠的传输,可靠信由网络层来保证。属于同一条虚电路的分组均按照同一路由进行转发,如果一个节点出故障,所有通过该节点的虚电路均不能工作。差错处理和流量控制可以由网络负责,也可以由用户主机负责。
数据报方式
网络层在采用数据报服务的时:
- 向上只提供简单灵活的、无连接的、尽最大努力交付的数据报服务。
- 在发送分组时不需要先建立连接。每一个分组(即ip数据报)独立发送,预期前后的分组无关(不进行编号)。
- 不提供服务质量的承诺。即所传送的分组可能出错、丢失、重复和失序(不按序到达终点),当然也不保证分组传送的时限。
网络层只会尽最大努力交付,不提供可靠的传输服务,如果主机进程之间需要可靠的传输服务,将交给传输层来保证这一点。网络层的这种设计思路使网络造价大大降低。
因特网的网络层是一个分组交换网。
每个分组都有完整的地址,独立选择路由进行转发,一个节点出现故障并不会影响其他分组的转发,下一次分组会选择其他路线,所以分组不一定会按序到达终点,也不负责差错处理和流量控制,这些都由用户主机负责。
那么网络层的“快递地址”是什么?对,就是ip地址。
IP地址
ip地址就是给每个链接在互联网上的主机(或路由器)分配一个在全世界范围唯一的32位的标识符。
ip地址的编址方法
分类的ip地址
将ip地址分为若干类。每一类地址都由两个固定长度的字段组成,网络号和主机号。
分类编址中,地址空间被分为五类:A、B、C、D、E类
D类地址用来进行多播,只有一个地址块。
E类地址只有一个地址块,为将来使用而保留。
ip地址的指派范围
要从一个分组的目的地址中提取其网络地址,路由器使用默认掩码来得到。
ip地址的一些重要特点:
- ip地址是一种分等级的地址结构,分两个等级的好处是:
- ip地址管理机构在分配时只分配网络号,剩下的主机号单位自行分配。方便ip地址的管理。
- 路由器仅根据目的主机所连接的网络号来转发分组(而不考虑目的主机号),这样就可以使路由表中的项目数大幅度减少,从而减小了路由表所占的存储空间。
- ip地址标志一个主机(或路由器)和一条链路的接口。
- 一个主机同时连接到两个网络上时,这种主机称为多归属机。
- 一个路由器至少应当有两个不同的ip地址。
- 用转发器或网桥连接起来的若干局域网仍为一个网络,因此这些局域网都具有同样的网络号。
- 素有分配到网络号的网络都是平等的。
在分类编址时,指派给一个组织的地址段是A、B、C类地址的一个地址块。这样就会出现一些问题,当给一个组织分配一个A类的地址的时候,没有哪个组织能使用完这么大地址块,所以有必要进一步划分,然后和其他组织共享。而分配一个C类地址时,主机数又太少不够用。所以出现了子网划分的思想。
子网划分
划分子网属于一个单位内部的事情。单位对外仍然表现为没有划分子网的网络。从主机号借用若干位作为子网号,主机号也就相应减少若干位。
划分子网后ip地址变为三级结构,划分子网只是把ip的主机号进行划分,不改变原来的网络号。
进行子网划分后无法通过ip数据报的首部判断是否进行了子网划分,使用子网掩码可以找出ip地址中的子网部分。
子网掩码长度32位,ip地址中对应网络号和子网号的位全为1,对应主机号的位全为0.
将ip地址和子网掩码进行逐位与运算可得到网络地址。所以进行子网划分后ip地址和子网掩码必须同时出现。
子网号全0和全1均不使用。一定程度上浪费了一些地址空间。
所以人们还设计了一种方案,无分类编址。
无分类的两级地址
网络前缀指明了网络,后缀指明了主机。前缀长度可以在1-32之间。
无分类编址时,如果我们要找出该地址所属的地址块,就必须在每个地址中包含其前缀长度
CIDR体系的一个优点就是路由聚合。路由聚合也称为构成超网。
全0地址,只能作为源地址,全1地址(受限广播地址)只能作为目的地址。二者在DHCP协议中使用。
127.0.0.0/8被用作环回地址,这个地址用来测试机器上的软件。在使用这个地址时,分组从来没离开过机器,只是简单的由协议软件返回。像“ping”这样的应用程序,可以发送以环回地址作为目的地址的分组,以便测试IPv4能否接收和处理分组。
私有地址不会在全球被识别。需要借助NAT路由器转换为全球识别的公有地址。
使用CIDR时,路由表中的每个项目由“网络前缀”和“下一条地址”组成。在查找路由表时可能会得到不止一个匹配结果。应当从匹配结果中选择具有最长网络前缀的路由:最长前缀匹配。(又称为最长匹配或最佳匹配)
路由器
路由器由输入端口、输出端口、路由选择处理器以及交换结构。
特定主机路由:为特定的主机指明一个路由(专线)。采用特定主机路可使网络管理人员更方便地控制网络和测试网络。
默认路由:一个统一的转发路由(其他未找到路由的数据报均从这里转发)。减少路由表所占用的空间和搜素路由表所用的时间。在一个网络只有很少的对外接口时很有用。
当路由器收到待转发的数据报,不是将下一跳路由器的ip地址填入数据报,而是送交下层的网络接口软件。
IP数据报
一个ip数据报由首部和数据两部分组成。
首部的前一部分是固定长度,共20字节,是所有ip数据报必须具有的。
**首部长度(HLEN)的单位为4字节,总长度单位为1字节,片偏移长度单位为8字节。**总长度报文的最大长度必须不超过最大传送单元MTU。
标识:标志了从源主机发出的一个数据报。当数据报离开主机后,此标识与源ip地址的组合必须唯一确定这个数据报。为了保证唯一性,ip协议使用了一个计数器来为数据报生成标号。计数器保存在主存储器中,保证唯一性。分片时,标号会复制到所有分片中。方便目的主机进行重装。
生存时间:路由器索经过的最大跳数。每经过一个路由器,这个数值就减1。
协议:定义使用此ip层服务的高层协议。有许多高层协议(如TCP、UDP、ICMP和IGMP等)的数据都能够被封装到ip数据报中。
标志位:第一位保留。第二位“不分片”(DF)位,DF = 1,表示不能分片,DF = 0,表示可以分片。第三位“更多分片”(MF)位,MF = 1,表示还有分片;MF = 0,表示没有分片。
首部检验和:只检验首部,不管数据部分。