TCP/IP协议 (图解+秒懂+史上最全)

文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上如下珍贵的学习资源:html


推荐: 疯狂创客圈 高质量 博文

高并发 必读 的精彩博文
nacos 实战(史上最全) sentinel (史上最全+入门教程)
Zookeeper 分布式锁 (图解+秒懂+史上最全) Webflux(史上最全)
SpringCloud gateway (史上最全) TCP/IP(图解+秒懂+史上最全)
10分钟看懂, Java NIO 底层原理 Feign原理 (图解)
更多精彩博文 ..... 请参见【 疯狂创客圈 高并发 总目录

史上最全 Java 面试题 28 专题 总目录

精心梳理、吐血推荐、史上最强、建议收藏 阿里、京东、美团、头条.... 随意挑、横着走!!!
1.Java算法面试题(史上最强、持续更新、吐血推荐) 2.Java基础面试题(史上最全、持续更新、吐血推荐)
3.JVM面试题(史上最强、持续更新、吐血推荐) 四、架构设计面试题 (史上最全、持续更新、吐血推荐)
五、Spring面试题 专题 六、SpringMVC面试题 专题
7.SpringBoot - 面试题(史上最强、持续更新) 八、Tomcat面试题 专题部分
9.网络协议面试题(史上最全、持续更新、吐血推荐) 十、TCP/IP协议(图解+秒懂+史上最全)
11.JUC并发包与容器 - 面试题(史上最强、持续更新) 十二、设计模式面试题 (史上最全、持续更新、吐血推荐)
13.死锁面试题(史上最强、持续更新) 15.Zookeeper 分布式锁 (图解+秒懂+史上最全)
1四、Redis 面试题 - 收藏版(史上最强、持续更新) 1六、Zookeeper 面试题(史上最强、持续更新)
1七、分布式事务面试题 (史上最全、持续更新、吐血推荐) 1八、一致性协议 (史上最全)
1九、Zab协议 (史上最全) 20、Paxos 图解 (秒懂)
2一、raft 图解 (秒懂) 2六、消息队列、RabbitMQ、Kafka、RocketMQ面试题 (史上最全、持续更新)
22.Linux面试题(史上最全、持续更新、吐血推荐) 2三、Mysql 面试题(史上最强、持续更新)
2四、SpringCloud 面试题 - 收藏版(史上最强、持续更新) 2五、Netty 面试题 (史上最强、持续更新)
2七、内存泄漏 内存溢出(史上最全) 2八、JVM 内存溢出 实战 (史上最全)

TCP/IP协议包含了一系列的协议,也叫TCP/IP协议族(TCP/IP Protocol Suite,或TCP/IP
Protocols),简称TCP/IP。TCP/IP协议族提供了点对点的连结机制,而且将传输数据帧的封装、寻址、传输、路由以及接收方式,都予以标准化。java

TCP/IP协议的分层模型

在展开介绍TCP/IP协议以前,首先介绍一下七层ISO模型。国际标准化组织ISO为了使网络应用更为普及,推出了OSI参考模型,即开放式系统互联(Open
System Interconnect)模型,
通常都叫OSI参考模型。OSI参考模型是ISO组织在1985年发布的网络互连模型,其含义就是为全部公司使用一个统一的规范来控制网络,这样全部公司遵循相同的通讯规范,网络就能互联互通了。程序员

OSI模型的七层框架

OSI模型定义了网络互连的七层框架(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层),每一层实现各自的功能和协议,并完成与相邻层的接口通讯。OSI模型各层的通讯协议,大体举例以下表所示:面试

表:OSI模型各层的通讯协议举例算法

应用层 HTTP、SMTP、SNMP、FTP、Telnet、SIP、SSH、NFS、RTSP、XMPP、Whois、ENRP、等等
表示层 XDR、ASN.一、SMB、AFP、NCP、等等
会话层 ASAP、SSH、RPC、NetBIOS、ASP、Winsock、BSD Sockets、等等
传输层 TCP、UDP、TLS、RTP、SCTP、SPX、ATP、IL、等等
网络层 IP、ICMP、IGMP、IPX、BGP、OSPF、RIP、IGRP、EIGRP、ARP、RARP、X.2五、等等
数据链路层 以太网、令牌环、HDLC、帧中继、ISDN、ATM、IEEE 802.十一、FDDI、PPP、等等
物理层 例如铜缆、网线、光缆、无线电等等

TCP/IP协议是Internet互联网最基本的协议,其在必定程度上参考了七层ISO模型。OSI模型共有七层,从下到上分别是物理层、数据链路层、网络层、运输层、会话层、表示层和应用层。可是这显然是有些复杂的,因此在TCP/IP协议中,七层被简化为了四个层次。TCP/IP模型中的各类协议,依其功能不一样,被分别归属到这四层之中,常被视为是简化事后的七层OSI模型。sql

TCP/IP协议与七层ISO模型的对应关系

TCP/IP协议与七层ISO模型的对应关系,大体以下图所示:
在这里插入图片描述编程

图:TCP/IP协议与七层ISO模型的对应关系设计模式

TCP/IP协议的应用层的主要协议有HTTP、Telnet、FTP、SMTP等,是用来读取来自传输层的数据或者将数据传输写入传输层;传输层的主要协议有UDP、TCP,实现端对端的数据传输;网络层的主要协议有ICMP、IP、IGMP,主要负责网络中数据包的传送等;链路层有时也称做数据链路层或网络接口层,主要协议有ARP、RARP,
一般包括操做系统中的设备驱动程序和计算机中对应的网络接口卡,它们一块儿处理与传输媒介(如电缆或其余物理设备)的物理接口细节。浏览器

(一)TCP/IP协议的应用层缓存

应用层包括全部和应用程序协同工做,并利用基础网络交换应用程序的业务数据的协议。一些特定的程序被认为运行在这个层上,该层协议所提供的服务能直接支持用户应用。应用层协议包括HTTP(万维网服务)、FTP(文件传输)、SMTP(电子邮件)、SSH(安全远程登录)、DNS(域名解析)以及许多其余协议。

(二)TCP/IP协议的传输层

传输层的协议,解决了诸如端到端可靠性问题,能确保数据可靠的到达目的地,甚至能保证数据按照正确的顺序到达目的地。传输层的主要功能大体以下:

(1)为端到端链接提供传输服务;

(2)这种传输服务分为可靠和不可靠的,其中TCP是典型的可靠传输,而UDP则是不可靠传输;

(3)为端到端链接提供流量控制、差错控制、QoS(Quality of
Service)服务质量等管理服务。

传输层主要有两个性质不一样的协议:TCP传输控制协议和UDP用户数据报协议。

TCP协议是一个面向链接的、可靠的传输协议,它提供一种可靠的字节流,能保证数据完整、无损而且按顺序到达。TCP尽可能接二连三地测试网络的负载而且控制发送数据的速度以免网络过载。另外,TCP试图将数据按照规定的顺序发送。

UDP协议是一个无链接的数据报协议,是一个“尽力传递”和“不可靠”协议,不会对数据包是否已经到达目的地进行检查,而且不保证数据包按顺序到达。

整体来讲,TCP协议传输效率低,但可靠性强;UDP协议传输效率高,但可靠性略低,适用于传输可靠性要求不高、体量小的数据(好比QQ聊天数据)。

(三)TCP/IP协议的网络层

TCP/IP协议网络层的做用是在复杂的网络环境中为要发送的数据报找到一个合适的路径进行传输。简单来讲,网络层负责将数据传输到目标地址,目标地址能够是多个网络经过路由器链接而成的某一个地址。另外,网络层负责寻找合适的路径到达对方计算机,并把数据帧传送给对方,网络层还能够实现拥塞控制、网际互连等功能。网络层协议的表明包括:ICMP、IP、IGMP等。

(四)TCP/IP协议的链路层

链路层有时也称做数据链路层或网络接口层,用来处理链接网络的硬件部分。该层既包括操做系统硬件的设备驱动、NIC(网卡)、光纤等物理可见部分,还包括链接器等一切传输媒介。在这一层,数据的传输单位为比特。其主要协议有ARP、RARP等。

图解 物理层:使用MAC解决设备的身份证问题

通讯的原始时代

好久好久以前,你不与任何其余电脑相链接,孤苦伶仃。

image

直到有一天,你但愿与另外一台电脑 B 创建通讯,因而大家各开了一个网口,用一根网线链接了起来。

image

用一根网线链接起来怎么就能"通讯"了呢?我能够给你讲 IO、讲中断、讲缓冲区,但这不是研究网络时该关心的问题。

若是你纠结,要么去研究一下操做系统是如何处理网络 IO 的,要么去研究一下包是如何被网卡转换成电信号发送出去的,要么就仅仅把它当作电脑里有个小人在开枪吧~

image.gif

反正,大家就是连起来了,而且能够通讯。

有一天,一个新伙伴 C 加入了,但聪明的大家很快发现,能够每一个人开两个网口,用一共三根网线,彼此相连。

image

随着愈来愈多的人加入,你发现身上开的网口实在太多了,并且网线密密麻麻,混乱不堪。(而实际上一台电脑根本开不了这么多网口,因此这种连线只在理论上可行,因此连不上的我就用红色虚线表示了,就是这么严谨哈哈~)

image

集线器的诞生

因而大家发明了一个中间设备,大家将网线都插到这个设备上,由这个设备作转发,就能够彼此之间通讯了,本质上和原来同样,只不过网口的数量和网线的数量减小了,再也不那么混乱。

image

你给它取名叫集线器,它仅仅是无脑将电信号转发到全部出口(广播),不作任何处理,你以为它是没有智商的,所以把人家定性在了物理层

image.gif

因为转发到了全部出口,那 BCDE 四台机器怎么知道数据包是否是发给本身的呢?

首先,你要给全部的链接到交换机的设备,都起个名字。原来大家叫 ABCD,但如今须要一个更专业的,全局惟一的名字做为标识,你把这个更高端的名字称为 MAC 地址

你的 MAC 地址是 aa-aa-aa-aa-aa-aa,你的伙伴 b 的 MAC 地址是 bb-bb-bb-bb-bb-bb,以此类推,不重复就好。

这样,A 在发送数据包给 B 时,只要在头部拼接一个这样结构的数据,就能够了。

image

B 在收到数据包后,根据头部的目标 MAC 地址信息,判断这个数据包的确是发给本身的,因而便收下

其余的 CDE 收到数据包后,根据头部的目标 MAC 地址信息,判断这个数据包并非发给本身的,因而便丢弃

image

虽然集线器使整个布局干净很多,但原来我只要发给电脑 B 的消息,如今却要发给链接到集线器中的全部电脑,这样既不安全,又不节省网络资源。

图解 数据链路:使用交换机解决MAC 地址映射问题

集线器的问题

若是把这个集线器弄得更智能一些,只发给目标 MAC 地址指向的那台电脑,就行了。

image

交换机的诞生

虽然只比集线器多了这一点点区别,但看起来彷佛有智能了,你把这东西叫作交换机。也正由于这一点点智能,你把它放在了另外一个层级,数据链路层

image

如上图所示,你是这样设计的。

交换机内部维护一张 MAC 地址表,记录着每个 MAC 地址的设备,链接在其哪个端口上。

MAC 地址 端口
bb-bb-bb-bb-bb-bb 1
cc-cc-cc-cc-cc-cc 3
aa-aa-aa-aa-aa-aa 4
dd-dd-dd-dd-dd-dd 5

假如你仍然要发给 B 一个数据包,构造了以下的数据结构从网口出去。

image

到达交换机时,交换机内部经过本身维护的 MAC 地址表,发现目标机器 B 的 MAC 地址 bb-bb-bb-bb-bb-bb 映射到了端口 1 上,因而把数据从 1 号端口发给了 B,完事~

你给这个经过这样传输方式而组成的小范围的网络,叫作以太网

固然最开始的时候,MAC 地址表是空的,是怎么逐步创建起来的呢?

假如在 MAC 地址表为空是,你给 B 发送了以下数据

image

因为这个包从端口 4 进入的交换机,因此此时交换机就能够在 MAC地址表记录第一条数据:

MAC:aa-aa-aa-aa-aa-aa-aa
端口:4

交换机看目标 MAC 地址(bb-bb-bb-bb-bb-bb)在地址表中并无映射关系,因而将此包发给了全部端口,也即发给了全部机器。

以后,只有机器 B 收到了确实是发给本身的包,因而作出了响应,响应数据从端口 1 进入交换机,因而交换机此时在地址表中更新了第二条数据:

MAC:bb-bb-bb-bb-bb-bb
端口:1

过程以下

image

通过该网络中的机器不断地通讯,交换机最终将 MAC 地址表创建完毕~

随着机器数量越多,交换机的端口也不够了,但聪明的你发现,只要将多个交换机链接起来,这个问题就垂手可得搞定~

image

你彻底不须要设计额外的东西,只须要按照以前的设计和规矩来,按照上述的接线方式便可完成全部电脑的互联,因此交换机设计的这种规则,真的很巧妙。你想一想看为何(好比 A 要发数据给 F)。

可是你要注意,上面那根红色的线,最终在 MAC 地址表中可不是一条记录呀,而是要把 EFGH 这四台机器与该端口(端口6)的映射所有记录在表中。

MAC 地址和端口的映射记录

最终,两个交换机将分别记录 A ~ H 全部机器的映射记录

左边的交换机

MAC 地址 端口
bb-bb-bb-bb-bb-bb 1
cc-cc-cc-cc-cc-cc 3
aa-aa-aa-aa-aa-aa 4
dd-dd-dd-dd-dd-dd 5
ee-ee-ee-ee-ee-ee 6
ff-ff-ff-ff-ff-ff 6
gg-gg-gg-gg-gg-gg 6
hh-hh-hh-hh-hh-hh 6

右边的交换机

MAC 地址 端口
bb-bb-bb-bb-bb-bb 1
cc-cc-cc-cc-cc-cc 1
aa-aa-aa-aa-aa-aa 1
dd-dd-dd-dd-dd-dd 1
ee-ee-ee-ee-ee-ee 2
ff-ff-ff-ff-ff-ff 3
gg-gg-gg-gg-gg-gg 4
hh-hh-hh-hh-hh-hh 6

这在只有 8 台电脑的时候还好,甚至在只有几百台电脑的时候,都还好,因此这种交换机的设计方式,已经足足支撑一阵子了。

但很遗憾,人是贪婪的动物,很快,电脑的数量就发展到几千、几万、几十万。

图解 传输层:IP地址和路由器

二层交换机的问题

交换机已经没法记录如此庞大的映射关系了。

此时你动了歪脑筋,你发现了问题的根本在于,连出去的那根红色的网线,后面不知道有多少个设备不断地链接进来,从而使得地址表愈来愈大。

那我可不可让那根红色的网线,接入一个新的设备,这个设备就跟电脑同样有本身独立的 MAC 地址,并且同时还能帮我把数据包作一次转发呢?

这个设备就是路由器,它的功能就是,做为一台独立的拥有 MAC 地址的设备,而且能够帮我把数据包作一次转发你把它定在了网络层。

image

注意,路由器的每个端口,都有独立的 MAC 地址

好了,如今交换机的 MAC 地址表中,只须要多出一条 MAC 地址 ABAB 与其端口的映射关系,就能够成功把数据包转交给路由器了,这条搞定。

那如何作到,把发送给 C 和 D,甚至是把发送给 DEFGH.... 的数据包,通通先发送给路由器呢?

不难想到这样一个点子,假如电脑 C 和 D 的 MAC 地址拥有共同的前缀,好比分别是

C 的 MAC 地址:FFFF-FFFF-CCCC D 的 MAC 地址:FFFF-FFFF-DDDD

那咱们就能够说,将目标 MAC 地址为 FFFF-FFFF-?开头的,通通先发送给路由器。

这样是否可行呢?答案是否认的。

IP地址的诞生

咱们先从现实中 MAC 地址的结构入手,MAC地址也叫物理地址、硬件地址,长度为 48 位,通常这样来表示

00-16-EA-AE-3C-40

它是由网络设备制造商生产时烧录在网卡的EPROM(一种闪存芯片,一般能够经过程序擦写)。

其中前 24 位(00-16-EA)表明网络硬件制造商的编号,后 24 位(AE-3C-40)是该厂家本身分配的,通常表示系列号。

只要不更改本身的 MAC 地址,MAC 地址在世界是惟一的。形象地说,MAC地址就如同身份证上的身份证号码,具备惟一性。

那若是你但愿向上面那样表示将目标 MAC 地址为 FFFF-FFFF-?开头的,统一从路由器出去发给某一群设备(后面会提到这实际上是子网的概念),那你就须要要求某一子网下通通买一个厂商制造的设备,要么你就须要要求厂商在生产网络设备烧录 MAC 地址时,提早按照你规划好的子网结构来定 MAC 地址,而且往后这个网络的结构都不能轻易改变。

这显然是不现实的。

因而你发明了一个新的地址,给每一台机器一个 32 位的编号,如:

11000000101010000000000000000001

你以为有些不清晰,因而把它分红四个部分,中间用点相连。

11000000.10101000.00000000.00000001

你还以为不清晰,因而把它转换成 10 进制。

192.168.0.1

最后你给了这个地址一个响亮的名字,IP 地址。如今每一台电脑,同时有本身的 MAC 地址,又有本身的 IP 地址,只不过 IP 地址是软件层面上的,能够随时修改,MAC 地址通常是没法修改的。

这样一个能够随时修改的 IP 地址,就能够根据你规划的网络拓扑结构,来调整了。

image

如上图所示,假如我想要发送数据包给 ABCD 其中一台设备,不论哪一台,我均可以这样描述,"将 IP 地址为 192.168.0 开头的所有发送给到路由器,以后再怎么转发,交给它!",巧妙吧。

路由器的诞生

路由器诞生了,专门负责IP地址的寻找。那报文交给路由器以后,路由器又是怎么把数据包准确转发给指定设备的呢?

别急咱们慢慢来。

咱们先给上面的组网方式中的每一台设备,加上本身的 IP 地址

image

image.gif

如今两个设备之间传输,除了加上数据链路层的头部以外,还要再增长一个网络层的头部。

假如 A 给 B 发送数据,因为它们直接连着交换机,因此 A 直接发出以下数据包便可,其实网络层没有体现出做用。

image

但假如 A 给 C 发送数据,A 就须要先转交给路由器,而后再由路由器转交给 C。因为最底层的传输仍然须要依赖以太网,因此数据包是分红两段的。

A ~ 路由器这段的包以下:

image

路由器到 C 这段的包以下:

image

好了,上面说的两种状况(A->B,A->C),相信细心的读者应该会有很多疑问,下面咱们一个个来展开。

子网的由来

A 给 C 发数据包,怎么知道是否要经过路由器转发呢?

答案:子网

若是源 IP 与目的 IP 处于一个子网,直接将包经过交换机发出去。

若是源 IP 与目的 IP 不处于一个子网,就交给路由器去处理。

好,那如今只须要解决,什么叫处于一个子网就行了。

  • 192.168.0.1 和 192.168.0.2 处于同一个子网

  • 192.168.0.1 和 192.168.1.1 处于不一样子网

这两个是咱们人为规定的,即咱们想表示,对于 192.168.0.1 来讲:

192.168.0.xxx 开头的,就算是在一个子网,不然就是在不一样的子网。

那对于计算机来讲,怎么表达这个意思呢?因而人们发明了子网掩码的概念

假如某台机器的子网掩码定为 255.255.255.0

这表示,将源 IP 与目的 IP 分别同这个子网掩码进行与运算****,相等则是在一个子网,不相等就是在不一样子网,就这么简单。

好比

  • A电脑:192.168.0.1 & 255.255.255.0 = 192.168.0.0

  • B电脑:192.168.0.2 & 255.255.255.0 = 192.168.0.0

  • C电脑:192.168.1.1 & 255.255.255.0 = 192.168.1.0

  • D电脑:192.168.1.2 & 255.255.255.0 = 192.168.1.0

那么 A 与 B 在同一个子网,C 与 D 在同一个子网,可是 A 与 C 就不在同一个子网,与 D 也不在同一个子网,以此类推。

image

因此若是 A 给 C 发消息,A 和 C 的 IP 地址分别 & A 机器配置的子网掩码,发现不相等,则 A 认为 C 和本身不在同一个子网,因而把包发给路由器,就无论了,以后怎么转发,A 不关心

A 如何知道,哪一个设备是路由器?

答案:在 A 上要设置默认网关

上一步 A 经过是否与 C 在同一个子网内,判断出本身应该把包发给路由器,那路由器的 IP 是多少呢?

其实说发给路由器不许确,应该说 A 会把包发给默认网关

对 A 来讲,A 只能直接把包发给同处于一个子网下的某个 IP 上,因此发给路由器仍是发给某个电脑,对 A 来讲也不关心,只要这个设备有个 IP 地址就行。

因此默认网关,就是 A 在本身电脑里配置的一个 IP 地址,以便在发给不一样子网的机器时,发给这个 IP 地址。

image

仅此而已!

路由表的由来(和Mac表的由来好像,都是逼出来的)

路由器如何知道C在哪里?

答案:路由表

如今 A 要给 C 发数据包,已经能够成功发到路由器这里了,最后一个问题就是,路由器怎么知道,收到的这个数据包,该从本身的哪一个端口出去,才能直接(或间接)地最终到达目的地 C 呢。

路由器收到的数据包有目的 IP 也就是 C 的 IP 地址,须要转化成从本身的哪一个端口出去,很容易想到,应该有个表,就像 MAC 地址表同样。

这个表就叫路由表

至于这个路由表是怎么出来的,有不少路由算法,本文不展开,由于我也不会哈哈~

不一样于 MAC 地址表的是,路由表并非一对一这种明确关系,咱们下面看一个路由表的结构。

目的地址 子网掩码 下一跳 端口
192.168.0.0 255.255.255.0 0
192.168.0.254 255.255.255.255 0
192.168.1.0 255.255.255.0 1
192.168.1.254 255.255.255.255 1

咱们学习一种新的表示方法,因为子网掩码其实就表示前多少位表示子网的网段,因此如 192.168.0.0(255.255.255.0) 也能够简写为 192.168.0.0/24

目的地址 下一跳 端口
192.168.0.0/24 0
192.168.0.254/32 0
192.168.1.0/24 1
192.168.1.254/32 1

这就很好理解了,路由表就表示,192.168.0.xxx 这个子网下的,都转发到 0 号端口,192.168.1.xxx 这个子网下的,都转发到 1 号端口。下一跳列尚未值,咱们先无论

配合着结构图来看(这里把子网掩码和默认网关都补齐了)

image

image.gif

刚才说的都是 IP 层,但发送数据包的数据链路层须要知道 MAC 地址,但是我只知道 IP 地址该怎么办呢?

答案:arp

假如你(A)此时不知道你同伴 B 的 MAC 地址(现实中就是不知道的,刚刚咱们只是假设已知),你只知道它的 IP 地址,你该怎么把数据包准确传给 B 呢?

答案很简单,在网络层,我须要把 IP 地址对应的 MAC 地址找到,也就是经过某种方式,找到 192.168.0.2 对应的 MAC 地址 BBBB

这种方式就是 arp 协议,同时电脑 A 和 B 里面也会有一张 arp 缓存表,表中记录着 IP 与 MAC 地址的对应关系。

IP 地址 MAC 地址
192.168.0.2 BBBB

一开始的时候这个表是空的,电脑 A 为了知道电脑 B(192.168.0.2)的 MAC 地址,将会广播一条 arp 请求,B 收到请求后,带上本身的 MAC 地址给 A 一个响应。此时 A 便更新了本身的 arp 表。

这样经过你们不断广播 arp 请求,最终全部电脑里面都将 arp 缓存表更新完整。

图解:整个传输过程

从各个节点的视角来看

电脑视角

  • 首先我要知道个人 IP 以及对方的 IP

  • 经过子网掩码判断咱们是否在同一个子网

  • 在同一个子网就经过 arp 获取对方 mac 地址直接扔出去

  • 不在同一个子网就经过 arp 获取默认网关的 mac 地址直接扔出去

交换机视角:

  • 我收到的数据包必须有目标 MAC 地址

  • 经过 MAC 地址表查映射关系

  • 查到了就按照映射关系从个人指定端口发出去

  • 查不到就全部端口都发出去

路由器视角:

  • 我收到的数据包必须有目标 IP 地址

  • 经过路由表查映射关系

  • 查到了就按照映射关系从个人指定端口发出去(不在任何一个子网范围,走其路由器的默认网关也是查到了)

  • 查不到则返回一个路由不可达的数据包

若是你嗅觉足够敏锐,你应该能够感觉到下面这句话:

网络层(IP协议)自己没有传输包的功能,包的实际传输是委托给数据链路层(以太网中的交换机)来实现的。

涉及到的三张表分别是

  • 交换机中有 MAC 地址表用于映射 MAC 地址和它的端口

  • 路由器中有路由表用于映射 IP 地址(段)和它的端口

  • 电脑和路由器中都有** arp 缓存表**用于缓存 IP 和 MAC 地址的映射关系

这三张表是怎么来的

  • MAC 地址表是经过以太网内各节点之间不断经过交换机通讯,不断完善起来的。

  • 路由表是各类路由算法 + 人工配置逐步完善起来的。

  • arp 缓存表是不断经过 arp 协议的请求逐步完善起来的。

知道了以上这些,目前网络上两个节点是如何发送数据包的这个过程,就彻底能够解释通了!

参考的网络拓扑图

那接下来咱们就放上参考的 最后一个网络拓扑图吧,请作好 战斗 准备!

image

这时路由器 1 链接了路由器 2,因此其路由表有了下一条地址这一个概念,因此它的路由表就变成了这个样子。若是匹配到了有下一跳地址的一项,则须要再次匹配,找到其端口,并找到下一跳 IP 的 MAC 地址。

也就是说找来找去,最终必须能映射到一个端口号,而后从这个端口号把数据包发出去。

目的地址 下一跳 端口
192.168.0.0/24 0
192.168.0.254/32 0
192.168.1.0/24 1
192.168.1.254/32 1
192.168.2.0/24 192.168.100.5
192.168.100.0/24 2
192.168.100.4/32 2

这时若是 A 给 F 发送一个数据包,能不能通呢?若是通的话整个过程是怎样的呢?

image

思考一分钟...

详细过程动画描述:

image

详细过程文字描述:

1. 首先 A(192.168.0.1)经过子网掩码(255.255.255.0)计算出本身与 F(192.168.2.2)并不在同一个子网内,因而决定发送给默认网关(192.168.0.254)

2. A 经过 ARP 找到 默认网关 192.168.0.254 的 MAC 地址。

3. A 将源 MAC 地址(AAAA)与网关 MAC 地址(ABAB)封装在数据链路层头部,又将源 IP 地址(192.168.0.1)和目的 IP 地址(192.168.2.2)(注意这里千万不要觉得填写的是默认网关的 IP 地址,从始至终这个数据包的两个 IP 地址都是不变的,只有 MAC 地址在不断变化)封装在网络层头部,而后发包

image

4. 交换机 1 收到数据包后,发现目标 MAC 地址是 ABAB,转发给路由器1

5. 数据包来到了路由器 1,发现其目标 IP 地址是 192.168.2.2,查看其路由表,发现了下一跳的地址是 192.168.100.5*

6. 因此此时路由器 1 须要作两件事,第一件是再次匹配路由表,发现匹配到了端口为 2,因而将其封装到数据链路层,最后把包从 2 号口发出去。

7. 此时路由器 2 收到了数据包,看到其目的地址是 192.168.2.2,查询其路由表,匹配到端口号为 1,准备从 1 号口把数据包送出去。

8. 但此时路由器 2 须要知道 192.168.2.2 的 MAC 地址了,因而查看其 arp 缓存,找到其 MAC 地址为 FFFF,将其封装在数据链路层头部,并从 1 号端口把包发出去。

9. 交换机 3 收到了数据包,发现目的 MAC 地址为 FFFF,查询其 MAC 地址表,发现应该从其 6 号端口出去,因而从 6 号端口把数据包发出去。

10.F 最终收到了数据包!**而且发现目的 MAC 地址就是本身,因而收下了这个包

HTTP报文传输原理

利用TCP/IP进行网络通讯时,数据包会按照分层顺序与对方进行通讯。发送端从应用层往下走,接收端从链路层往上走。从客户端到服务器的数据,每一帧数据的传输的顺序都为:应用层->运输层->网络层->链路层->链路层->网络层->运输层->应用层。

HTTP报文传输过程

以一个HTTP请求的传输为例,请求从HTTP客户端(如浏览器)和HTTP服务端应用的传输过程,大体以下图所示:
在这里插入图片描述

图:HTTP请求报文的分层传输过程

数据封装和分用

接下来,为你们介绍一下数据封装和分用。

数据经过互联网传输的时候不多是光秃秃的不加标识,若是这样数据就会乱。因此数据在发送的时候,须要加上特定标识,加上特定标识的过程叫作数据的封装,在数据使用的时候再去掉特定标识,去掉特定标识的过程就叫作分用。TCP/IP协议的数据封装和分用过程,大体以下图所示:
在这里插入图片描述

图:TCP/IP协议的数据封装和分用过程

在数据封装时,数据通过每一个层都会打上该层特定标识,添加上头部。

在传输层封装时,添加的报文首部时要存入一个应用程序的标识符,不管TCP和UDP都用一个16位的端口号来表示不一样的应用程序,而且都会将源端口和目的端口存入报文首部中。

在网络层封装时,IP首部会标识处理数据的协议类型,或者说标识出网络层数据帧所携带的上层数据类型,如TCP、UDP、ICMP、IP、IGMP等等。
具体来讲,会在IP首部中存入一个长度为8位的数值,称做协议域:
1表示为ICMP协议、2表示为IGMP协议、6表示为TCP协议、17表示为UDP协议、等等。IP首部还会标识发送方地址(源IP)和接收方地址(目标IP)。

在链路层封装时,网络接口分别要发送和接收IP、ARP和RARP等多种不一样协议的报文,所以也必须在以太网的帧首部中加入某种形式的标识,以指明所处理的协议类型,为此,以太网的报文帧的首部也有一个16位的类型域,标识出以太网数据帧所携带的上层数据类型,如IPv四、ARP、IPV六、PPPoE等等。

数据封装和分用的过程大体为:发送端每经过一层会增长该层的首部,接收端每经过一层则删除该层的首部。

整体来讲,TCP/IP分层管理、数据封装和分用的好处:分层以后若需改变相关设计,只需替换变更的层。各层之间的接口部分规划好以后,每一个层次内部的设计就能够自由改动。层次化以后,设计也变得相对简单:各个层只需考虑分派给本身的传输任务。

TCP/IP与OSI的区别主要有哪些呢?除了TCP/IP与OSI在分层模块上稍有区别,更重要的区别为:OSI参考模型注重“通讯协议必要的功能是什么”,而TCP/IP则更强调“在计算机上实现协议应该开发哪一种程序”。

实际上,在传输过程当中,数据报文会在不一样的物理网络之间传递,仍是以一个HTTP请求的传输为例,请求在不一样物理网络之间的传输过程,大体以下图所示:
在这里插入图片描述

图:HTTP请求在不一样物理网络之间的传输过程

数据包在不一样物理网络之间的传输过程当中,网络层会经过路由器去对不一样的网络之间的数据包进行存储、分组转发处理。构造互连网最简单的方法是把两个或多个网络经过路由器进行链接。路由器能够简单理解为一种特殊的用于网络互连的硬件盒,其做用是为不一样类型的物理网络提供链接:以太网、令牌环网、点对点的连接和FDDI(光纤分布式数据接口)等等。

物理网络之间经过路由器进行互连,随着增长不一样类型的物理网络,可能会有不少个路由器,可是对于应用层来讲仍然是同样的,TCP协议栈为你们屏蔽了物理层的复杂性。总之,物理细节和差别性的隐藏,使得互联网TCP/IP传输的功能变得很是强大。

接下来,开始为你们介绍与传输性能有密切关系的内容:TCP传输层的三次握手创建链接,四次挥手释放链接。不过在此以前,还得先介绍一下TCP报文协议。

TCP协议的报文格式

在TCP/IP协议栈中,IP协议层只关心如何使数据可以跨越本地网络边界的问题,而不关心数据如何传输。总体TCP/IP协议栈,共同配合一块儿解决数据如何经过许许多多个点对点通路,顺利传输到达目的地。一个点对点通路被称为一“跳”(hop),经过TCP/IP协议栈,网络成员可以在许多“跳”的基础上创建相互的数据通路。

传输层TCP协议提供了一种面向链接的、可靠的字节流服务,其数据帧格式,大体以下图所示:
在这里插入图片描述

图:传输层TCP协议的数据帧格式

一个传输层TCP协议的数据帧,大体包含如下字段:

(一)源端口号

源端口号表示报文的发送端口,占16位。源端口和源IP地址组合起来,能够标识报文的发送地址。

(二)目的端口号

目的端口号表示报文的接收端口,占16位。目的端口和目的IP地址相结合,能够标识报文的接收地址。

TCP协议是基于IP协议的基础上传输的,TCP报文中的源端口号+源IP,与TCP报文中的目的端口号+目的IP一块儿,组合起来惟一性的肯定一条TCP链接。

(三)序号(Sequence Number)

TCP传输过程当中,在发送端出的字节流中,传输报文中的数据部分的每个字节都有它的编号。序号(Sequence
Number)占32位,发起方发送数据时,都须要标记序号。

序号(Sequence Number)的语义与SYN控制标志(Control
Bits)的值有关。根据控制标志(Control Bits)中的SYN是否为1,序号(Sequence
Number)表达不一样的含义:

(1)当SYN = 1时,当前为链接创建阶段,此时的序号为初始序号ISN((Initial Sequence
Number),经过算法来随机生成序号;

(2)当SYN = 0时在数据传输正式开始时,第一个报文的序号为 ISN +
1,后面的报文的序号,为前一个报文的SN值+TCP报文的净荷字节数(不包含TCP头)。好比,若是发送端发送的一个TCP帧的净荷为12byte,序号为5,则发送端接着发送的下一个数据包的时候,序号的值应该设置为5+12=17。

在数据传输过程当中,TCP协议经过序号(Sequence
Number)对上层提供有序的数据流。发送端能够用序号来跟踪发送的数据量;接收端能够用序号识别出重复接收到的TCP包,从而丢弃重复包;对于乱序的数据包,接收端也能够依靠序号对其进行排序。

(四)确认序号(Acknowledgment Number)

确认序号(Acknowledgment
Number)标识了报文接收端指望接收的字节序列。若是设置了ACK控制位,确认序号的值表示一个准备接收的包的序列码,注意,它所指向的是准备接收的包,也就是下一个指望接收的包的序列码。

举个例子,假设发送端(如Client)发送3个净荷为1000byte、起始SN序号为1的数据包给Server服务端,Server每收到一个包以后,须要回复一个ACK响应确认数据包给Client。ACK响应数据包的ACK
Number值,为每一个Client包的为SN+包净荷,既表示Server已经确认收到的字节数,还表示指望接收到的下一个Client发送包的SN序号,具体的ACK值以下图左边的正常传输部分所示。
在这里插入图片描述

图:传输过程的确认序号(Acknowledgment Number)值示例图

在上图的左边部分,Server第1个ACK包的ACK
Number值为1001,是经过Client第1个包的SN+包净荷=1+1000计算获得,表示指望第2个Client包的SN序号为1001;Server第2个ACK包的ACK
Number值为2001,为Client第2个包的SN+包净荷=2001,表示指望第3个Server包的SN为2001,以此类推。

若是发生错误,假设Server在处理Client的第二个发送包异常,Server仍然回复一个ACK
Number值为1001的确认包,则Client的第二个数据包须要重复发送,具体的ACK值如上图右边的正常传输部分所示。

只有控制标志的ACK标志为1时,数据帧中的确认序号ACK
Number才有效。TCP协议规定,链接创建后,全部发送的报文的ACK必须为1,也就是创建链接后,全部报文的确认序号有效。若是是SYN类型的报文,其ACK标志为0,故没有确认序号。

(五)头部长度

该字段占用4位,用来表示TCP报文首部的长度,单位是4bit位。其值所表示的并非字节数,而是头部的所含有的32bit的数目(或者倍数),或者4个字节的倍数,因此TCP头部最多能够有60字节(4*15=60)。没有任何选项字段的TCP头部长度为20字节,因此其头部长度为5,能够经过20/4=5计算获得。

(六)预留6位

头部长度后面预留的字段长度为6位,做为保留字段,暂时没有什么用处。

(七)控制标志

控制标志(Control
Bits)共6个bit位,具体的标志位为:URG、ACK、PSH、RST、SYN、FIN。6个标志位的说明,以下表所示。

表:TCP报文控制标志(Control Bits)说明

标志位 说明
URG 占1位,表示紧急指针字段有效。URG位指示报文段里的上层实体(数据)标记为“紧急”数据。当URG=1时,其后的紧急指针指示紧急数据在当前数据段中的位置(相对于当前序列号的字节偏移量),TCP接收方必须通知上层实体。
ACK 占1位,置位ACK=1表示确认号字段有效;TCP协议规定,接创建后全部发送的报文的ACK必须为1;当ACK=0时,表示该数据段不包含确认信息。当ACK=1时,表示该报文段包括一个对已被成功接收报文段的确认序号Acknowledgment Number,该序号同时也是下一个报文的预期序号。
PSH 占1位,表示当前报文须要请求推(push)操做;当PSH=1时,接收方在收到数据后当即将数据交给上层,而不是直到整个缓冲区满。
RST 占1位,置位RST=1表示复位TCP链接;用于重置一个已经混乱的链接,也可用于拒绝一个无效的数据段或者拒绝一个链接请求。若是数据段被设置了RST位,说明报文发送方有问题发生。
SYN 占1位,在链接创建时用来同步序号。当SYN=1而ACK=0时,代表这是一个链接请求报文。对方若赞成创建链接,则应在响应报文中使SYN=1和ACK=1。 综合一下,SYN置1就表示这是一个链接请求或链接接受报文。
FIN 占1位,用于在释放TCP链接时,标识发送方比特流结束,用来释放一个链接。当 FIN = 1时,代表此报文的发送方的数据已经发送完毕,并要求释放链接。

在链接创建的三次握手过程当中,若只是单个SYN置位,表示的只是创建链接请求。若是SYN和ACK同时置位为1,表示的创建链接以后的响应。

(八)窗口大小:

长度为16位,共2个字节。此字段用来进行流量控制。流量控制的单位为字节数,这个值是本端指望一次接收的字节数。

(九)校验和:

长度为16位,共2个字节。对整个TCP报文段,即TCP头部和TCP数据进行校验和计算,接收端用于对收到的数据包进行验证。

(十)紧急指针:

长度为16位,2个字节。它是一个偏移量,和SN序号值相加表示紧急数据最后一个字节的序号。

以上十项内容是TCP报文首部必须的字段,也称固有字段,长度为20个字节。接下来是TCP报文的可选项和填充部分。

(十一)可选项和填充部分

可选项和填充部分的长度为4n字节(n是整数),该部分是根据须要而增长的选项。若是不足4n字节,要加填充位,使得选项长度为32位(4字节)的整数倍,具体的作法是在这个字段中加入额外的零,以确保TCP头是32位(4字节)的整数倍。

最多见的选项字段是MSS(Maximum Segment
Size最长报文大小),每一个链接方一般都在通讯的第一个报文段(SYN标志为1的那个段)中指明这个选项字段,表示当前链接方所能接受的最大报文段的长度。

因为可选项和填充部分不是必须的,因此TCP报文首部最小长度为20个字节。

至此,TCP报文首部的字段,就所有介绍完了。TCP报文首部的后面,接着的是数据部分,不过数据部分是可选的。在一个链接创建和一个链接终止时,双方交换的报文段仅有TCP首部。若是一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据,好比在处理超时的过程当中,也会发送不带任何数据的报文段。

整体来讲,TCP协议的可靠性,主要经过如下几点来保障:

(1)应用数据分割成TCP认为最适合发送的数据块。这部分是经过MSS(最大数据包长度)选项来控制的,一般这种机制也被称为一种协商机制,MSS规定了TCP传往另外一端的最大数据块的长度。值得注意的是,MSS只能出如今SYN报文段中,若一方不接收来自另外一方的MSS值,则MSS就定为536字节。通常来说,MSS值仍是越大越好,这样能够提升网络的利用率。

(2)重传机制。设置定时器,等待确认包,若是定时器超时尚未收到确认包,则报文重传。

(3)对首部和数据进行校验。

(4)接收端对收到的数据进行排序,而后交给应用层。

(5)接收端丢弃重复的数据。

(6)TCP还提供流量控制,主要是经过滑动窗口来实现流量控制。

至此TCP协议的数据帧格式介绍完了。接下来开始为你们重点介绍:TCP传输层的三次握手创建链接,四次挥手释放链接。

TCP的三次握手

TCP链接的创建时,双方须要通过三次握手,而断开链接时,双方须要通过四次分手,那么,其三次握手和四次分手分别作了什么呢?又是如何进行的呢?

一般状况下,创建链接的双方,由一端打开一个监听套接字(ServerSocket)来监听来自请求方的TCP(Socket)链接,当服务器端监听开始时,必须作好准备接受外来的链接,在Java中该操做经过建立一个ServerSocket服务监听套接字实例来完成,此操做会调用底层操做系统(如Linux)的C代码中三个函数socket()、bind()、listen()
来完成。开始监听以后,服务器端就作好接受外来链接的准备,若是监听到创建新链接的请求,会开启一个传输套接字,称之为被动打开(Passive
Open)。

一段简单的服务端监听新链接请求,而且被动打开(Passive
Open)传输套接字的Java示例代码,具体以下:

public class SocketServer {

public static void main(String[] args) {

try {

// 建立服务端socket

ServerSocket serverSocket = new ServerSocket(8080);

//循环监听等待客户端的链接

while(true){

//监听到客户端链接,传输套接字被动开启

Socket socket = serverSocket.accept();

//开启线程进行链接的IO处理

ServerThread thread = new ServerThread(socket);

thread.start();

......

}

} catch (Exception e) {

// 处理异常

e.printStackTrace();

}

}

}

客户端在发起链接创建时,Java代码经过建立Socket实例,调用底层的connect(…)方法,主动打开(Active
Open)Socket链接。套接字监听方在收到请求以后,监听方和发起方(客户端)之间就会创建一条的链接通道,该通道由双方IP和双方端口所惟一肯定。

一段简单的客户端链接主动打开(Active Open)的Java示例代码,具体以下:

public class SocketClient {

public static void main(String[] args) throws InterruptedException {

try {

// 和服务器建立链接

Socket socket = new Socket("localhost",8080);

// 写入给监听方的输出流

OutputStream os = socket.getOutputStream();

…..

// 读取监听方的输入流

InputStream is = socket.getInputStream();

…..

} catch (Exception e) {

e.printStackTrace();

}

}

}

三次握手过程

TCP链接的创建时,双方须要通过三次握手,具体过程以下:

(1)第一次握手:Client进入SYN_SENT状态,发送一个SYN帧来主动打开传输通道,该帧的SYN标志位被设置为1,同时会带上Client分配好的SN序列号,该SN是根据时间产生的一个随机值,一般状况下每间隔4ms会加1。除此以外,SYN帧还会带一个MSS(最大报文段长度)可选项的值,表示客户端发送出去的最大数据块的长度。

(2)第二次握手:Server端在收到SYN帧以后,会进入SYN_RCVD状态,同时返回SYN+ACK帧给Client,主要目的在于通知Client,Server端已经收到SYN消息,如今须要进行确认。Server端发出的SYN+ACK帧的ACK标志位被设置为1,其确认序号AN(Acknowledgment
Number)值被设置为Client的SN+1;SYN+ACK帧的SYN标志位被设置为1,SN值为Server端生成的SN序号;SYN+ACK帧的MSS(最大报文段长度)表示的是Server端的最大数据块长度。

(3)第三次握手:Client在收到Server的第二次握手SYN+ACK确认帧以后,首先将本身的状态会从SYN_SENT变成ESTABLISHED,表示本身方向的链接通道已经创建成功,Client能够发送数据给Server端了。而后,Client发ACK帧给Server端,该ACK帧的ACK标志位被设置为1,其确认序号AN(Acknowledgment
Number)值被设置为Server端的SN序列号+1。还有一种状况,Client可能会将ACK帧和第一帧要发送的数据,合并到一块儿发送给Server端。

(4)Server端在收到Client的ACK帧以后,会从SYN_RCVD状态会进入ESTABLISHED状态,至此,Server方向的通道链接创建成功,Server能够发送数据给Client,TCP的全双工链接创建完成。

三次握手的图解

三次握手的交互过程,具体以下图所示:
在这里插入图片描述

图:TCP创建的链接时三次握手示意图

Client和Server完成了三次握手后,双方就进入了数据传输的阶段。数据传输完成后,链接将断开,链接断开的过程须要经历四次挥手。

TCP的四次挥手

业务数据通讯完成以后,TCP链接开始断开(或者拆接)的过程,在这个过程当中链接的每一个端的都能独立地、主动的发起,断开的过程TCP协议使用了四路挥手操做。

四次挥手具体过程

四次挥手具体过程,具体以下:

(1)第一次挥手:主动断开方(能够是客户端,也能够是服务器端),向对方发送一个FIN结束请求报文,此报文的FIN位被设置为1,而且正确设置Sequence
Number(序列号)和Acknowledgment
Number(确认号)。发送完成后,主动断开方进入FIN_WAIT_1状态,这表示主动断开方没有业务数据要发送给对方,准备关闭SOCKET链接了。

(2)第二次挥手:正常状况下,在收到了主动断开方发送的FIN断开请求报文后,被动断开方会发送一个ACK响应报文,报文的Acknowledgment
Number(确认号)值为断开请求报文的Sequence Number
(序列号)加1,该ACK确认报文的含义是:“我赞成你的链接断开请求”。以后,被动断开方就进入了CLOSE-WAIT(关闭等待)状态,TCP协议服务会通知高层的应用进程,对方向本地方向的链接已经关闭,对方已经没有数据要发送了,若本地还要发送数据给对方,对方依然会接受。被动断开方的CLOSE-WAIT(关闭等待)还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

主动断开方在收到了ACK报文后,由FIN_WAIT_1转换成FIN_WAIT_2状态。

(3)第三次挥手:在发送完成ACK报文后,被动断开方还能够继续完成业务数据的发送,待剩余数据发送完成后,或者CLOSE-WAIT(关闭等待)截止后,被动断开方会向主动断开方发送一个FIN+ACK结束响应报文,表示被动断开方的数据都发送完了,而后,被动断开方进入LAST_ACK状态。

(4)第四次挥手:主动断开方收在到FIN+ACK断开响应报文后,还须要进行最后的确认,向被动断开方发送一个ACK确认报文,而后,本身就进入TIME_WAIT状态,等待超时后最终关闭链接。处于TIME_WAIT状态的主动断开方,在等待完成2MSL的时间后,若是期间没有收到其余报文,则证实对方已正常关闭,主动断开方的链接最终关闭。

被动断开方在收到主动断开方的最后的ACK报文之后,最终关闭了链接,本身啥也无论了。

四次挥手图解

四次挥手的所有交互过程,具体以下图所示:
在这里插入图片描述

图:TCP创建的链接时四次挥手的示意图

处于TIME_WAIT状态的主动断开方,在等待完成2MSL的时间后,才真正关闭链接通道,其等待的时间为何是2MSL呢?

2MSL翻译过来就是两倍的MSL。MSL全称为Maximum Segment
Lifetime,指的是一个TCP报文片断在网络中最大的存活时间,具体来讲,2MSL对应于一次消息的来回(一个发送和一个回复)所需的最大时间。若是直到2MSL,主动断开方都没有再一次收到对方的报文(如FIN报文),则能够推断ACK已经被对方成功接收,此时,主动断开方将最终结束本身的TCP链接。因此,TCP的TIME_WAIT状态也称为2MSL等待状态。

有关MSL的具体的时间长度,在RFC1122协议中推荐为2分钟。在SICS(瑞典计算机科学院)开发的一个小型开源的TCP/IP协议栈——LwIP开源协议栈中MSL默认为1分钟。在源自Berkeley的TCP协议栈实现中MSL默认长度为30秒。整体来讲,TIME_WAIT(2MSL)等待状态的时间长度,通常维持在1-4分钟之间。

经过三次握手创建链接和四次挥手拆除链接,一次TCP的链接创建及拆除,至少进行7次通讯,可见其成本是很高的。

三次握手、四次挥手的常见面试题

有关TCP的链接创建的三次握手及拆除过程的四次挥手的面试问题,是技术面试过程当中的出现频率很高的重点和难点问题,常见问题大体以下:

问题(1):为何关闭链接的须要四次挥手,而创建链接却只要三次握手呢?

关闭链接时,被动断开方在收到对方的FIN结束请求报文时,极可能业务数据没有发送完成,并不能当即关闭链接,被动方只能先回复一个ACK响应报文,告诉主动断开方:“你发的FIN报文我收到了,只有等到我全部的业务报文都发送完了,我才能真正的结束,在结束以前,我会发你FIN+ACK报文的,你先等着”。因此,被动断开方的确认报文,须要拆开成为两步,故整体就须要四步挥手。

而在创建链接场景中,Server端的应答能够稍微简单一些。当Server端收到Client端的SYN链接请求报文后,其中ACK报文表示对请求报文的应答,SYN报文用来表示服务端的链接也已经同步开启了,而ACK报文和SYN报文之间,不会有其余报文须要发送,故而能够合二为一,能够直接发送一个SYN+ACK报文。因此,在创建链接时,只须要三次握手便可。

问题(2):为何链接创建的时候是三次握手,能够改为两次握手吗?

三次握手完成两个重要的功能:一是双方都作好发送数据的准备工做,并且双方都知道对方已准备好;二是双方完成初始SN序列号的协商,双方的SN序列号在握手过程当中被发送和确认。

若是把三次握手改为两次握手,可能发生死锁。两次握手的话,缺失了Client的二次确认ACK帧,假想的TCP创建的链接时二次挥手,能够以下图所示:
在这里插入图片描述

图:假想的TCP创建的链接时二次握手的示意图

在假想的TCP创建的链接时二次握手过程当中,Client发送Server发送一个SYN请求帧,Server收到后发送了确认应答SYN+ACK帧。按照两次握手的协定,Server认为链接已经成功地创建了,能够开始发送数据帧。这个过程当中,若是确认应答SYN+ACK帧在传输中被丢失,Client没有收到,Client将不知道Server是否已准备好,也不知道Server的SN序列号,Client认为链接还未创建成功,将忽略Server发来的任何数据分组,会一直等待Server的SYN+ACK确认应答帧。而Server在发出的数据帧后,一直没有收到对应的ACK确认后就会产生超时,重复发送一样的数据帧。这样就造成了死锁。

问题(3):为何主动断开方在TIME-WAIT状态必须等待2MSL的时间?

缘由之一:主动断开方等待2MSL的时间,是为了确保两端都能最终关闭。假设网络是不可靠的,被动断开方发送FIN+ACK报文后,其主动方的ACK响应报文有可能丢失,这时候的被动断开方处于LAST-ACK状态的,因为收不到ACK确认被动方一直不能正常的进入CLOSED状态。在这种场景下,被动断开方会超时重传FIN+ACK断开响应报文,若是主动断开方在2MSL时间内,收到这个重传的FIN+ACK报文,会重传一次ACK报文,后再一次从新启动2MSL计时等待,这样,就能确保被动断开方能收到ACK报文,从而能确保被动方顺利进入到CLOSED状态。只有这样,双方都可以确保关闭。反过来讲,若是主动断开方在发送完ACK响应报文后,不是进入TIME_WAIT状态去等待2MSL时间,而是当即释放链接,则将没法收到被动方重传的FIN+ACK报文,因此不会再发送一次ACK确认报文,此时处于LAST-ACK状态的被动断开方,没法正常进入到CLOSED状态。

缘由之二:防止“旧链接的已失效的数据报文”出如今新链接中。主动断开方在发送完最后一个ACK报文后,再通过2MSL,才能最终关闭和释放端口,这就意味着,相同端口的新TCP新链接,须要在2MSL的时间以后,才可以正常的创建。2MSL这段时间内,旧链接所产生的全部数据报文,都已经从网络中消失了,从而,确保了下一个新的链接中不会出现这种旧链接请求报文。

问题(4):若是已经创建了链接,可是Client端忽然出现故障了怎么办?

TCP还设有一个保活计时器,Client端若是出现故障,Server端不能一直等下去,这样会浪费系统资源。每收到一次Client客户端的数据帧后,Server端都的保活计时器会复位。计时器的超时时间一般是设置为2小时,若2小时尚未收到Client端的任何数据帧,Server端就会发送一个探测报文段,之后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,Server端就认为Client端出了故障,接着就关闭链接。若是以为保活计时器的两个多小时的间隔太长,能够自行调整TCP链接的保活参数。

相关文章
相关标签/搜索