TCP/IP协议

TCP/IP协议

基本概念

  TCP/IP模型是一系列网络协议的总称,这些协议的目的,就是使计算机之间可以进行信息交换。所谓"协议"可以理解成机器之间交谈的语言,每一种协议都有自己的目的。TCP/IP模型一共包括几百种协议,对互联网上交换信息的各个方面都做了规定。

TCP/IP协议簇分层

  提到协议分层,我们很容易联想到ISO-OSI的七层协议经典架构,但是TCP/IP协议簇的结构则稍有不同。

OSI分层


  由于OSI模型和协议比较复杂,所以并没有得到广泛的应用。
而TCP/IP(transfer control protocol/internet protocol,传输控制协议/网际协议)模型因其开放性和易用性在实践中得到了广泛的应用,TCP/IP协议栈也成为互联网的主流协议。

TCP/IP协议簇的四层结构

  • 应用层(包括OSI的应用层,表示层和会话层):Telnet,FTP,SMTP,DNS,HTTP
  • 传输层:TCP,UDP
  • 网际层:IP,ARP,RARP
  • 网络接口层(包括数据链路层和物理层):局域网LAN,广域网WAN

  当应用程序用TCP传送数据时,数据被送入协议簇中,然后逐个通过每一层直到被当作一串比特流送入网络。其中每一层对收到的数据都要增加一些首部信息(有时还要增加尾部信息),该过程如图所示。

端口号

端口用一个 16 bit 端口号进行标识,有效的端口号为0~65535。端口号只具有本地意义,即端口号只是为了标志本计算机应用层中的各进程。在因特网中不同计算机的相同端口号是没有联系的。
熟知端口:常用的应用层程序固定使用的熟知端口 (well-known port),其数值一般为0~1023,例如,FTP用21,TELNET用23,SMTP用25,DNS用53,HTTP用80,等等。
一般端口:用来随时分配给请求通信的客户进程。端口的数值范围是1024~65535。一般端口是随机分配的,其数值即端口号就表示了相应的应用程序。

Socket套接字

IP地址+端口号;一个连接是由它两端的套接字地址唯一确定的。

因特网域名

是由一串用“点”分隔的字符组成的Internet上某一台计算机或计算机组的名称。作用:便于记忆。

应用层

  应用层负责处理特定的应用程序细节。下面介绍常用的协议:

  • FTP:文件传输协议
  • Telnet:远程登录协议
  • HTTP:超文本传输协议
  • SMTP:简单邮件传输协议
  • DNS:域名系统,域名集合和IP地址集合的相互映射。

传输层

  主要为两台主机上的应用程序提供端到端的通信。下面介绍常用的协议(在后面的部分详细介绍):

  • TCP:传输控制协议
  • UDP:用户数据报协议

网际层

  主要是根据IP地址为分组选择最佳路由,路由器(主要完成数据包转发功能,即收到分组后,根据分组中包含的目的地址,在转发表中选择适当的输出端口,转发分组)位于这一层。

  • IP协议(网际协议):提供的是一种不可靠的服务,它只是尽可能快地把分组从源结点送到目的结点,但是并不提供任何可靠性保证,同时被TCP和UDP使用。
  • ARP(地址解析协议):IP地址→MAC地址(硬件地址,唯一)
  • RARP(逆地址解析协议):MAC地址→IP地址
  • ICMP(因特网控制报文协议):允许主机或路由器报告差错情况和提供有关异常情况的报告。PING (Packet InterNet Groper): 用来测试两个主机之间的连通性。使用了 ICMP 回送请求与回送回答报文。PING 是应用层直接使用网络层 ICMP 的例子,它没有通过传输层的 TCP 或UDP。当网络中存在网关或防火墙时,由于其防护和数据包过滤功能,连通性测试结果可能不正确。

网络接口层

  实现与具体的网络的连接。

TCP和UDP

   传输控制协议 TCP ( Transmission Control Protocol )和用户数据报协议 UDP( User Datagram Protocol ) 。

比较

TCP:
优点:TCP提供一种面向连接的、全双工的、可靠的字节流(为了方便传输,将大块数据分割成以报文段(segment)为单位的数据包进行管理)服务。保证接收顺序。有点像打电话:要和某个人通话,首先拿起电话,拨号码,通话,然后挂断。适用于要求可靠传输的应用,如文件传输等
缺点:由于 TCP 要提供面向连接的,可靠的传输服务,因此不可避免地增加了许多控制开销。并且不提供广播或多播服务。

UDP:
无连接,可靠性较低。有点像寄信,每个报文(信件)带有完整的目的地址,并且每一个报文都独立于其他报文,由系统选定的路线传递。不保证到达,也不保证顺序,但传输开销小,速度快,并且可以用于多播和广播。UDP协议的可靠性必须由上层应用来提供。适用于实时应用(IP电话、视频会议、直播等)

TCP工作原理

TCP如何提供可靠地服务

  • 面向连接(三次握手建立连接,四次挥手断开连接)。
  • 超时重传和确认策略:当 TCP 发出一个报文段后,它会启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;
  • 流量控制(滑动窗口算法):TCP 双方都有固定大小的缓冲区,流量控制的原理是利用滑动窗口控制数据发送速度,避免缓冲区溢出导致数据丢失。
  • 拥塞控制:TCP 利用慢启动和拥塞避免等算法实现了拥塞控制。
  • CRC校验机制:发送端按照特定算法计算出 TCP 报文段的检验和并存储在 TCP 首部中的对应字段上,接收端在接收时会以同样的方式计算校验和,如果不一致,说明报文段出现错误,会将其丢弃。
  • 序号与确认序号:对乱序的数据进行排序后发给应用层,并丢弃重复的数据。


  TCP最多有60个字节的首部,如果没有任选字段,正常的长度是20字节。包括

  • 16位源端口号;
  • 16位目的端口号(每个TCP段都包含源和目的端的端口号,用于寻找发端和收端应用进程。这两个值加上IP首部中的源端IP地址和目的端IP地址可以唯一确定一个TCP连接);
  • 32位序号(指的是本报文段所发送的数据的第一个字节的序号);
  • 32位确认号(期望收到对方的下一个报文段的数据的第一个字节的序号);
  • 32位数据偏移(指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远);
  • 紧急比特 URG —— 当 URG=1 时,表明此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。
  • 确认比特 ACK —— 只有当 ACK =1 时确认号字段才有效。当 ACK= 0 时,确认号无效。
  • 推送比特 PSH (Push) —— 接收方 TCP 收到推送比特置 1 的报文段,就尽快地交付给接收应用进程,而不再等到整个缓存都填满了后再向上交付。
  • 复位比特 RST (Reset) —— 当 RST=1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立连接。
  • 同步比特 SYN —— 同步比特 SYN 置为 1,就表示这是一个连接请求或连接接受报文。
  • 终止比特 FIN (Finsh) —— 用来释放一个连接。当FIN =1 时,表明此报文段的发送端的数据已发送完毕,并要求释放连接。
  • 窗口字段 —— 占 2 字节。窗口字段用来控制对方发送的数据量,单位为字节。TCP 连接的一端根据设置的缓存空间大小确定自己的接收窗口大小,然后通知对方以确定对方的发送窗口的上限。
  • 检验和 —— 占 2 字节。检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。
  • 紧急指针字段 —— 占 16 bit。紧急指针指出在本报文段中的紧急数据的最后一个字节的序号。
  • 选项字段 —— 长度可变。TCP 首部可以有多达40字节的可选信息,用于把附加信息传递给终点,或用来对齐其它选项。
  • 填充字段 —— 这是为了使整个首部长度是 4 字节的整数倍。

  TCP 的确认是对接收到的数据的最高序号表示确认。接收端返回的确认号是已收到的数据的最高序号加 1。因此确认号表示接收端期望下次收到的数据中的第一个数据字节的序号。为提高效率,TCP可以累积确认,即在接收多个报文段后,一次确认。

TCP三次握手

  TCP 的连接和建立都是采用客户服务器方式。主动发起连接建立的应用进程叫做客户端(client)。被动等待连接建立的应用进程叫做服务器(server)。

  • 第一次握手:Client将同步比特SYN置为1(表示这是一个连接请求或连接接受报文),并发送初始报文段序号seq = x(sequence,含义:表明发送数据时的第一个数据字节的序号,每次发送都会自增,自增数值就是发送的字节数,建立连接时连接报文段长度为1)。发送完报文段1之后,客户端进入 SYN-SENT 状态,等待服务器的确认。
  • 第二次握手:Server收到报文段后,如同意,则发回确认。令SYN=1,ACK=1(表示确认号字段ack有效),ack=x+1(含义:表示x之前的我都收到了,希望对方下一次发送x+1),并选择服务器端初始报文段序号 seq=y(含义:表明服务器传送数据时的第一个数据字节的序号,因为TCP是双向传输)。发送完报文段2后,服务器进入 SYN-RECEIVED 状态。
  • 第三次握手:Client收到确认后,则令确认比特ACK=1,发送报文段序号seq=x+1,希望下一次接收的报文段序号ack=y+1,并将该数据报发送给Server。服务器收到后,则成功建立连接。双方都进入 ESTABLISHED 状态,表示连接已建立。

四次挥手断开连接

(主动方为A,被动方为B)

  1. 客户端发送关闭连接的报文段,FIN 标志位1,请求关闭连接,并停止发送数据。序号字段 seq = x (等于之前发送的所有数据的最后一个字节的序号加一),然后客户端会进入 FIN-WAIT-1 状态,等待来自服务器的确认报文;
  2. 服务器收到 FIN 报文后,发回确认报文,ACK = 1, ack = x + 1,并带上自己的序号 seq = y,然后服务器就进入 CLOSE-WAIT 状态。服务器还会通知上层的应用程序对方已经释放连接,此时 TCP 处于半关闭状态,也就是说客户端已经没有数据要发送了,但是服务器还可以发送数据,客户端也还能够接收。客户端收到服务器的 ACK 报文段后随即进入 FIN-WAIT-2 状态,此时还能收到来自服务器的数据,直到收到 FIN 报文段。
  3. 服务器发送完所有数据后,会向客户端发送 FIN 报文段,各字段值如图所示,随后服务器进入 LAST-ACK 状态,等待来自客户端的确认报文段。
  4. 户端收到来自服务器的 FIN 报文段后,向服务器发送 ACK 报文,随后进入 TIME-WAIT 状态,等待 2MSL(2 * Maximum Segment Lifetime,两倍的报文段最大存活时间) ,这是任何报文段在被丢弃前能在网络中存在的最长时间,常用值有30秒、1分钟和2分钟。如无特殊情况,客户端会进入 CLOSED 状态。服务器在接收到客户端的 ACK 报文后会随即进入 CLOSED 状态,由于没有等待时间,一般而言,服务器比客户端更早进入 CLOSED 状态。

为什么建立连接是三次握手,而关闭连接却是四次挥手呢?

  由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。A发送了FIN=1仅仅表示A不再发送新的数据报了,但是B未必将全部数据都发送给了A,所以B要将所有数据发送过去,并且收到了确认,才能断开连接。

为什么A发送完ACK=1还要保持2*MSL时间?

  1. MSL即报文最大生存时间。保证若B收不到ACK=1重发FIN=1时,A还未关闭。不过这个不是主要原因,毕竟数据已经交互完成了。
  2. 如果不等待2MSL的话, 那么如果正好一个新连接又建立在相同的端口上, 那么上次的FIN包可能被新的连接收到, 导致新的连接出现问题。MSL一般设置30秒,1分钟或者2分钟。

TCP 建立连接为什么要三次握手而不是两次?

  1. 防止已过期的连接请求报文突然又传送到服务器,因而产生错误
    在双方两次握手即可建立连接的情况下,假设客户端发送 A 报文段请求建立连接,由于网络原因造成 A 暂时无法到达服务器,服务器接收不到请求报文段就不会返回确认报文段,客户端在长时间得不到应答的情况下重新发送请求报文段 B,这次 B 顺利到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,客户端在收到 确认报文后也进入 ESTABLISHED 状态,双方建立连接并传输数据,之后正常断开连接。此时姗姗来迟的 A 报文段才到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,但是已经进入 CLOSED 状态的客户端无法再接受确认报文段,更无法进入 ESTABLISHED 状态,这将导致服务器长时间单方面等待,造成资源浪费。
  2. 三次握手才能让双方均确认自己和对方的发送和接收能力都正常
    第一次握手:客户端只是发送处请求报文段,什么都无法确认,而服务器可以确认自己的接收能力和对方的发送能力正常;
    第二次握手:客户端可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;
    第三次握手:服务器可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;
    可见三次握手才能让双方都确认自己和对方的发送和接收能力全部正常,这样就可以愉快地进行通信了。
  3. 告知对方自己的初始序号值,并确认收到对方的初始序号值
    TCP 实现了可靠的数据传输,原因之一就是 TCP 报文段中维护了序号字段和确认序号字段,也就是图中的 seq 和 ack,通过这两个字段双方都可以知道在自己发出的数据中,哪些是已经被对方确认接收的。这两个字段的值会在初始序号值得基础递增,如果是两次握手,只有发起方的初始序号可以得到确认,而另一方的初始序号则得不到确认。

有一种网络攻击是利用了 TCP 建立连接机制的漏洞,你了解吗?这个问题怎么解决?

答:在三次握手过程中,服务器在收到了客户端的 SYN 报文段后,会分配并初始化连接变量和缓存,并向客户端发送 SYN + ACK 报文段,这相当于是打开了一个“半开连接 (half-open connection)”,会消耗服务器资源。如果客户端正常返回了 ACK 报文段,那么双方可以正常建立连接,否则,服务器在等待一分钟后会终止这个“半开连接”并回收资源。这样的机制为 SYN洪泛攻击 (SYN flood attack)提供了机会,这是一种经典的 DoS攻击 (Denial of Service,拒绝服务攻击),所谓的拒绝服务攻击就是通过进行攻击,使受害主机或网络不能提供良好的服务,从而间接达到攻击的目的。在 SYN 洪泛攻击中,攻击者发送大量的 SYN 报文段到服务器请求建立连接,但是却不进行第三次握手,这会导致服务器打开大量的半开连接,消耗大量的资源,最终无法进行正常的服务。
解决方法:SYN Cookies,现在大多数主流操作系统都有这种防御系统。SYN Cookies 是对 TCP 服务器端的三次握手做一些修改,专门用来防范 SYN 洪泛攻击的一种手段。它的原理是,在服务器接收到 SYN 报文段并返回 SYN + ACK 报文段时,不再打开一个半开连接,也不分配资源,而是根据这个 SYN 报文段的重要信息 (包括源和目的 IP 地址,端口号可一个秘密数),利用特定散列函数计算出一个 cookie 值。这个 cookie 作为将要返回的SYN + ACK 报文段的初始序列号(ISN)。当客户端返回一个 ACK 报文段时,服务器根据首部字段信息计算 cookie,与返回的确认序号(初始序列号 + 1)进行对比,如果相同,则是一个正常连接,然后分配资源并建立连接,否则拒绝建立连接。

简单解释一下上面的状态

三次握手:

  • LISTEN(监听)状态
  • SYN-SEND(同步已发送)状态
  • SYN-RCVD(同步收到,received)状态
  • ESTABLISHED(已建立连接,established)状态

滑动窗口算法

  TCP 连接双方的主机都为该连接设置了发送缓存和接收缓存,这些缓存起到了蓄水池的作用,我们肯定不能把上层应用程序发来的数据一股脑儿发送到网络中,而是利用发送缓存将其缓存起来,然后再按一定的速率通过网络发送给对方,而接收缓存的作用是把对方传来的数据先缓存起来,等到己方应用程序有空的时候再来取走数据。

我们可以把发送方的发送缓存中的字节分为以下四类,每个编号对应一个字节:

发送缓存中的字节分类

  • 第一类:已发送且已确认,这些数据已经发送成功并已经被确认的数据,比如图中的前31个bytes,这些数据其实的位置是在窗口之外了,下一步将被移出发送缓存。窗口内顺序最低的字节被确认之后,窗口左边界会向右移动,称为窗口合拢。
    第二类:已发送但未收到确认,这部分数据已经被发送出去,但是还没有收到接收端的 ACK,认为并没有完成发送,这部分数据属于窗口内的数据。
    第三类:未发送但是接收方已经准备好接收,这部分是尽快发送的数据,这部分数据已经被加载到缓存中,也在发送窗口中,正在等待发送,其实这个窗口是完全有接收方告知的,接收方告知当前可以接受这些数据,所以发送方需要尽快的发送。
    第四类:未发送且接收方未准备好接收,这些数据属于未发送,同时接收端也不允许发送的,因为这些数据已经超出了发送端所接收的范围。

发送窗口:图中的黑色框就是发送方的发送窗口,其大小由两个因素决定:1、接收方的提供的窗口大小 (TCP 报文段首部中的 window 字段),发送方在三次握手阶段首次得到这个值,之后的通信过程中接收方会根据自己的可用缓存对这个值进行动态调整;2、发送方会根据网络情况维护一个拥塞窗口变量。发送窗口的大小取这两个值的最小值。对于发送方来说,发送窗口分为两部分,分别是已经发送的部分(已经发送了,但是没有收到ACK)和可用窗口,接收端允许发送但是没有发送的那部分称为可用窗口。即
接收窗口 rwnd :这是接收端根据其目前的接收缓存大小所许诺的最新的窗口值,是来自接收端的流量控制。接收端将此窗口值放在 TCP 报文的首部中的窗口字段,传送给发送端。
拥塞窗口 cwnd:是发送端根据自己估计的网络拥塞程度而设置的窗口值,是来自发送端的流量控制。

  发送端的发送窗口的上限值应当取为接收端窗口 rwnd 和拥塞窗口 cwnd 这两个变量中较小的一个,即应按以下公式确定:
发送窗口的上限值= Min [rwnd, cwnd]

接收窗口:对于接收端也是有一个接收窗口的,类似发送端,接收端的数据有3个分类,因为接收端并不需要等待ACK所以它没有类似的接收并确认了的分类,情况如下

  • Received and ACK Not Send to Process:这部分数据属于接收了数据但是还没有被上层的应用程序接收;
  • Received Not ACK: 已经接收,但是还没有回复 ACK;
  • Not Received:有空位,还没有被接收的数据。

滑动窗口是如何滑动的

累积确认概念:TCP 并不是每一个报文段都会回复一个 ACK ,可能会对两个报文段发送一个ACK,也可能会对多个报文段发送 1 个 ACK,这称为累积确认。
下面举例说明一下窗口滑动的过程:

  • 在握手过程中,接收方通告的窗口大小为20字节,所以发送方将发送窗口大小设置为20字节。
  • 从图中的"上一个发送窗口的位置"(灰色虚线框)说起, 32-51号字节恰好处于发送窗口中,恰好20个字节,假设 TCP 将其分为 4 个报文段进行发送,每个报文段 5 个字节数据,分别记为 seg1 32-36, seg2 37-41, seg3 42-46, seg4 47-51。
  • TCP 将有序发送 seg1、seg2、seg3和seg4四个报文段,如果这四个报文段都顺利到达接收方,接收方将发回一个累积确认的 ACK 报文段,其中 ack = 52,代表希望收到下一个报文段的起始字节编号,报文段中也会继续通告窗口大小,如果还是20字节,那么发送方的窗口将整体向右移动20字节,如果通告的窗口值变小,比如变成15,那么发送窗口左边界移动20字节,右边界移动15字节。
  • 如果在发送过程中 seg2 报文段丢失,而其他三个报文段正常到达接收方,那么接收方会现接受这三个报文段,然后返回 ACK 报文段,ack = 37,表示希望收到的下一个报文段的起始字节号为37,也就是seg2报文段。如果通告窗口值未发生变化,发送方在收到 ACK 后会将窗口整体右移5个字节,也就变成了图中的位置。
  • 由于 seg2 还未收到 ACK,当重传计时器超时后,发送方会重新发送 seg2,此时52-56号字节又落到了发送窗口中,TCP 将其封装成报文段进行发送,如果接收方全部顺利收到,会返回一个累积确认的 ACK,ack = 57,表示希望收到的喜爱个报文段的起始字节号为57。

TCP 的拥塞控制

  • 什么是拥塞控制:当数据从一个大的管道 (比如一个快速局域网)向一个较小的管道 (比如较慢的广域网)发送的时候就会发生拥塞,还有一种情况就是当多个输入流到达一个路由器,而路由器的输出流小于这些输入流的总和时,也会发生拥塞。于是 TCP 提供了响应的机制来应对这种情况,也就是 TCP 的拥塞控制。
  • 拥塞窗口 (congestion window,简写为 cwnd)的概念:拥塞窗口是由发送方根据网络状况维护的一个变量,用于控制自己的数据发送速率。前文提到了发送方的发送窗口受两个变量约束,一是接收方通告的窗口大小值,二就是发送方自身的拥塞窗口,实际的发送窗口大小取二者最小值。

如何实现拥塞控制

TCP 一共使用了四种算法来实现拥塞控制:
1、慢启动 (slow-start);
2、拥塞避免 (congestion avoidance);
3、快速重传 (fast retransmit);
4、快速恢复 (fast recovery)。

慢启动算法

  慢启动算法的目的是为了保证TCP发送方发送分组的速率应该匹配收到该分组确认报文的速率。在刚开始发送时,可先将拥塞窗口 cwnd 设置为一个最大报文段 MSS 的数值。在每收到一个对新的报文段的确认后,将拥塞窗口增加至 2倍 MSS 的数值。用这样的方法逐步增大发送端的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。 下图中我们假定接收端窗口足够大,因此现在发送窗口的数值等于拥塞窗口的数值。

ssthresh:慢启动门限(slow start threshold,简写为 ssthresh):

  • 当cnwd < ssthresh,使用慢启动算法
  • 当 cnwd = ssthresh,既可使用慢启动算法,也可以使用拥塞避免算法
  • 当 cnwd > ssthresh,使用拥塞避免算法

拥塞避免算法

当拥塞窗口大小达到初始 ssthresh 值时,转而采用拥塞避免算法。拥塞避免并非完全能够避免拥塞,是说在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞,思路:让拥塞窗口 cwnd 缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口加一。无论是在慢启动阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认,虽然没有收到确认可能是其他原因的分组丢失,但是因为无法判定,所以都当做拥塞来处理),就把慢开始门限设置为出现拥塞时的发送窗口大小的一半。然后把拥塞窗口设置为 1,执行慢启动算法。

快速重传

快速重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方),而不要等到自己发送数据时捎带确认。快速重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。由于不需要等待设置的重传计时器到期,能尽早重传未被确认的报文段,能提高整个网络的吞吐量。

快速恢复

当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把 ssthresh 门限减半。但是接下去并不执行慢启动算法。考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢启动算法,而是将 cwnd 设置为 ssthresh 的大小, 然后执行拥塞避免算法。

TCP 粘包与拆包

TCP 粘包和拆包的原因

我们知道 TCP 是以字节流的方式传输数据,传输的最小单位为一个报文段(segment)。TCP 首部 中有个选项 (Options)的字段,常见的选项为 MSS (Maximum Segment Size最大消息长度),它是收发双方协商通信时每一个报文段所能承载的最大有效数据的长度。数据链路层每次传输的数据有个最大限制MTU (Maximum Transmission Unit),一般是1500比特,超过这个量要分成多个报文段,MSS 则是这个最大限制减去 TCP 的首部,光是要传输的数据的大小,一般为1460比特。换算成字节,也就是180多字节。
MSS = MTU - Header
TCP 为提高性能,发送端会将需要发送的数据发送到发送缓存,等待缓存满了之后,再将缓存中的数据发送到接收方。同理,接收方也有接收缓存这样的机制,来接收数据。

上面这些是发生 TCP 粘包和拆包的前提,下面是具体的原因:

  • 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。
  • 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。
  • 应用程序写入数据小于剩余缓存大小,网卡将应用多次写入的数据先缓存起来,然后一起发送到网络上,这将会发生粘包。
  • 接收数据端的应用层没有及时读取接收缓存中的数据,将发生粘包。

TCP 粘包和拆包的解决方案

  • 设置定长消息,服务端每次读取既定长度的内容作为一条完整消息。
  • 设置消息边界,数据结尾尾增加特殊字符分割。
  • 使用带消息头的协议,消息头存储消息开始标识及消息长度信息,接收方获取消息头的时候解析出消息长度,然后向后读取该长度的内容。

TCP 的重传机制

  TCP 每发送一个报文段,就对这个报文段设置一次计时器。只要计时器设置的重传时间到达,但还没有收到确认,就要重传这一报文段。超时重传时间一般为:2*MSL(报文最大生存时间)

IP地址

   IP 地址就是给每个连接在因特网上的主机(或路由器)分配一个在全世界范围是惟一的 32 bit 的标识符。


[127 ,<任意>] 表示回送地址,用于网络软件测试。例如 127.0.0.1 一旦使用该地址发送数据,则立即返回。

子网编址的实现

   从主机号中借用若干个比特作为子网号,而主机号也就相应减少了若干个比特。
IP 地址 = [ 网络号,子网号,主机号 ]
注意:

  • 子网号在网外是不可见的,仅在子网内使用。
  • 子网号的位数是可变的,为了反映有多少位用于表示子网号,采用子网掩码 ( mask ) 。

子网掩码32位

   32位子网掩码中,网络地址、子网地址部分对应“1” ,主机地址部分为“0” 。
   子网号 = 子网掩码与 IP 地址做逻辑“与”运算的结果

子网数和子网掩码的计算

1)子网数:\(2^x-2\)。x是主机位中被占用的表示子网比特的数目,或者说1的个数。减2是指减去子网位全1和全0,它们默认是无效的。例如,11100000能产生\(2^3–2\)个子网。
2) 每个子网的主机数:\(2^y-2\)。y是未被占用的主机位的比特数目,或者说0的个数。如,在C类网中,对应子网掩码11100000,则可得$ 2^5–2$,每个子网30个主机。
记住一些常用数字:\(2^7=128\),\(2^6=64\),\(2^5=32\),\(2^4=16\)。快速计算一个数的二进制:
比如224=128+64+32,因此1110 0000。
3) 基数:256-子网掩码。

例子1:设有一个网络地址为 172.168.0.0,要在此网络中划分14个子网,问:需要多少位表示子网?子网掩码的点分十进制数值是多少?每个子网地址是什么?

   首先由\(2^7<172<2^7+2^6\),知道这是一个B类网络。子网数= \(2^x-2\),则x=4,需借用 4位表示子网。B类网络网络地址和主机地址各为16位,网络掩码为 255.255.0.0 。划分子网后,又使用主机地址部分的最高4 位表示子网,则其对应十进制数值为128+64+32+16=240。网络掩码为 255.255.240.0 。
   子网基数=256-240=16,N=1~14,则子网地址为 172.168.16.0, 172.168.32.0, 172.168.48.0, 172.168.64.0, 172.168.80.0, 172.168.96.0, 172.168.112.0, 172.168.128.0, 172.168.144.0, 172.168.160.0, 172.168.176.0, 172.168.192.0, 172.168.208.0, 172.168.224.0。
   每个子网内表示主机的地址位为12位,则子网内有效主机数为 2^12-2=4094。网络内总的主机数为4094×14=57316。

无分类域间路由选择 CIDR

IP地址 = 网络前缀+主机号/网络前缀位数
   比如:128.14.32.0/20 表示的地址块共有 2^12 个地址(斜线后面的 20 是网络前缀的比特数,所以主机号的比特数是 12)。
最小地址:128.14.32.0
最大地址:128.14.47.255,前20位相同,47.255为0010 1111.1111 1111,全 0 和全 1 的主机地址一般不使用。
128.14.32.0/20的掩码(但不叫子网掩码)为:1111 1111 1111 1111 1111 0000 0000 0000,即255.255.240.0

超网
CIDR地址块中C类地址的数目,比如上面的16个C类地址。

最长前缀匹配
   使用 CIDR 时,路由表中的每个项目由“网络前缀”和“下一跳地址”组成。在查找路由表时可能会得到不止一个匹配结果。
应当从匹配结果中选择具有最长网络前缀的路由:最长前缀匹配(longest-prefix matching)。网络前缀越长,其地址块就越小,因而路由就越具体。

例子:

收到的分组的目的地址 D = 206.0.71.130
路由表中的项目:206.0.68.0/22
206.0.71.128/25

posted @ 2020-04-01 22:52  何必等明天  阅读(947)  评论(0编辑  收藏  举报