TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输。TCP/IP 协议采用4层结构,分别是应用层、传输层、网络层和链路层,每一层都呼叫它的下一层所提供的协议来完成自己的需求。由于我们大部分时间都工作在应用层,下层的事情不用我们操心;其次网络协议体系本身就很复杂庞大,入门门槛高,因此很难搞清楚TCP/IP的工作原理,通俗一点讲就是,一个主机的数据要经过哪些过程才能发送到对方的主机上。 接下来,我们就来探索一下这个过程。
0、物理介质
物理介质就是把电脑连接起来的物理手段,常见的有光纤、双绞线,以及无线电波,它决定了电信号(0和1)的传输方式,物理介质的不同决定了电信号的传输带宽、速率、传输距离以及抗干扰性等等。
TCP/IP协议栈分为四层,每一层都由特定的协议与对方进行通信,而协议之间的通信最终都要转化为 0 和 1 的电信号,通过物理介质进行传输才能到达对方的电脑,因此物理介质是网络通信的基石。
下面我们通过一张图先来大概了解一下TCP/IP协议的基本框架:
当通过http发起一个请求时,应用层、传输层、网络层和链路层的相关协议依次对该请求进行包装并携带对应的首部,最终在链路层生成以太网数据包,以太网数据包通过物理介质传输给对方主机,对方接收到数据包以后,然后再一层一层采用对应的协议进行拆包,最后把应用层数据交给应用程序处理。
网络通信就好比送快递,商品外面的一层层包裹就是各种协议,协议包含了商品信息、收货地址、收件人、联系方式等,然后还需要配送车、配送站、快递员,商品才能最终到达用户手中。
一般情况下,快递是不能直达的,需要先转发到对应的配送站,然后由配送站再进行派件。
配送车就是物理介质,配送站就是网关, 快递员就是路由器,收货地址就是IP地址,联系方式就是MAC地址。
快递员负责把包裹转发到各个配送站,配送站根据收获地址里的省市区,确认是否需要继续转发到其他配送站,当包裹到达了目标配送站以后,配送站再根据联系方式找到收件人进行派件。
有了整体概念以后,下面我们详细了解一下各层的分工。
1、链路层
网络通信就是把有特定意义的数据通过物理介质传送给对方,单纯的发送 0 和 1 是没有意义的,要传输有意义的数据,就需要以字节为单位对 0 和 1 进行分组,并且要标识好每一组电信号的信息特征,然后按照分组的顺序依次发送。以太网规定一组电信号就是一个数据包,一个数据包被称为一帧, 制定这个规则的协议就是以太网协议。一个完整的以太网数据包如下图所示:
整个数据帧由首部、数据和尾部三部分组成,首部固定为14个字节,包含了目标MAC地址、源MAC地址和类型;数据最短为46个字节,最长为1500个字节,如果需要传输的数据很长,就必须分割成多个帧进行发送;尾部固定为4个字节,表示数据帧校验序列,用于确定数据包在传输过程中是否损坏。因此,以太网协议通过对电信号进行分组并形成数据帧,然后通过物理介质把数据帧发送给接收方。那么以太网如何来识接收方的身份呢?
以太网规协议定,接入网络的设备都必须安装网络适配器,即网卡, 数据包必须是从一块网卡传送到另一块网卡。而网卡地址就是数据包的发送地址和接收地址,也就是帧首部所包含的MAC地址,MAC地址是每块网卡的身份标识,就如同我们身份证上的身份证号码,具有全球唯一性。MAC地址采用十六进制标识,共6个字节, 前三个字节是厂商编号,后三个字节是网卡流水号,例如 4C-0F-6E-12-D2-19
有了MAC地址以后,以太网采用广播形式,把数据包发给该子网内所有主机,子网内每台主机在接收到这个包以后,都会读取首部里的目标MAC地址,然后和自己的MAC地址进行对比,如果相同就做下一步处理,如果不同,就丢弃这个包。
所以链路层的主要工作就是对电信号进行分组并形成具有特定意义的数据帧,然后以广播的形式通过物理介质发送给接收方。
2、网络层
对于上面的过程,有几个细节问题值得我们思考:
发送者如何知道接收者的MAC地址?
发送者如何知道接收者和自己同属一个子网?
如果接收者和自己不在同一个子网,数据包如何发给对方?
为了解决这些问题,网络层引入了三个协议,分别是IP协议、ARP协议、路由协议。
【1】IP协议
通过前面的介绍我们知道,MAC地址只与厂商有关,与所处的网络无关,所以无法通过MAC地址来判断两台主机是否属于同一个子网。
因此,网络层引入了IP协议,制定了一套新地址,使得我们能够区分两台主机是否同属一个网络,这套地址就是网络地址,也就是所谓的IP地址。
IP地址目前有两个版本,分别是IPv4和IPv6,IPv4是一个32位的地址,常采用4个十进制数字表示。IP协议将这个32位的地址分为两部分,前面部分代表网络地址,后面部分表示该主机在局域网中的地址。由于各类地址的分法不尽相同,以C类地址192.168.24.1为例,其中前24位就是网络地址,后8位就是主机地址。因此, 如果两个IP地址在同一个子网内,则网络地址一定相同。为了判断IP地址中的网络地址,IP协议还引入了子网掩码, IP地址和子网掩码通过按位与运算后就可以得到网络地址。
由于发送者和接收者的IP地址是已知的(应用层的协议会传入), 因此我们只要通过子网掩码对两个IP地址进行AND运算后就能够判断双方是否在同一个子网了。
【2】ARP协议
即地址解析协议,是根据IP地址获取MAC地址的一个网络层协议。其工作原理如下:
ARP首先会发起一个请求数据包,数据包的首部包含了目标主机的IP地址,然后这个数据包会在链路层进行再次包装,生成以太网数据包,最终由以太网广播给子网内的所有主机,每一台主机都会接收到这个数据包,并取出标头里的IP地址,然后和自己的IP地址进行比较,如果相同就返回自己的MAC地址,如果不同就丢弃该数据包。ARP接收返回消息,以此确定目标机的MAC地址;与此同时,ARP还会将返回的MAC地址与对应的IP地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。cmd输入 arp -a 就可以查询本机缓存的ARP数据。
【3】路由协议
通过ARP协议的工作原理可以发现,ARP的MAC寻址还是局限在同一个子网中,因此网络层引入了路由协议,首先通过IP协议来判断两台主机是否在同一个子网中,如果在同一个子网,就通过ARP协议查询对应的MAC地址,然后以广播的形式向该子网内的主机发送数据包;如果不在同一个子网,以太网会将该数据包转发给本子网的网关进行路由。网关是互联网上子网与子网之间的桥梁,所以网关会进行多次转发,最终将该数据包转发到目标IP所在的子网中,然后再通过ARP获取目标机MAC,最终也是通过广播形式将数据包发送给接收方。
而完成这个路由协议的物理设备就是路由器,在错综复杂的网络世界里,路由器扮演者交通枢纽的角色,它会根据信道情况,选择并设定路由,以最佳路径来转发数据包。
【4】IP数据包
在网络层被包装的数据包就叫IP数据包,IPv4数据包的结构如下图所示:
IP数据包由首部和数据两部分组成,首部长度为20个字节,主要包含了目标IP地址和源IP地址,目标IP地址是网关路由的线索和依据;数据部分的最大长度为65515字节,理论上一个IP数据包的总长度可以达到65535个字节,而以太网数据包的最大长度是1500个字符,如果超过这个大小,就需要对IP数据包进行分割,分成多帧发送。
所以,网络层的主要工作是定义网络地址,区分网段,子网内MAC寻址,对于不同子网的数据包进行路由。
3、传输层
链路层定义了主机的身份,即MAC地址, 而网络层定义了IP地址,明确了主机所在的网段,有了这两个地址,数据包就从可以从一个主机发送到另一台主机。但实际上数据包是从一个主机的某个应用程序发出,然后由对方主机的应用程序接收。而每台电脑都有可能同时运行着很多个应用程序,所以当数据包被发送到主机上以后,是无法确定哪个应用程序要接收这个包。
因此传输层引入了UDP协议来解决这个问题,为了给每个应用程序标识身份,UDP协议定义了端口,同一个主机上的每个应用程序都需要指定唯一的端口号,并且规定网络中传输的数据包必须加上端口信息。 这样,当数据包到达主机以后,就可以根据端口号找到对应的应用程序了。UDP定义的数据包就叫做UDP数据包,结构如下所示:
UDP数据包由首部和数据两部分组成,首部长度为8个字节,主要包括源端口和目标端口;数据最大为65527个字节,整个数据包的长度最大可达到65535个字节。
UDP协议比较简单,实现容易,但它没有确认机制, 数据包一旦发出,无法知道对方是否收到,因此可靠性较差,为了解决这个问题,提高网络可靠性,TCP协议就诞生了,TCP即传输控制协议,是一种面向连接的、可靠的、基于字节流的通信协议。简单来说TCP就是有确认机制的UDP协议,每发出一个数据包都要求确认,如果有一个数据包丢失,就收不到确认,发送方就必须重发这个数据包。
为了保证传输的可靠性,TCP 协议在 UDP 基础之上建立了三次对话的确认机制,也就是说,在正式收发数据前,必须和对方建立可靠的连接。由于建立过程较为复杂,我们在这里做一个形象的描述:
主机A:我想发数据给你,可以么?
主机B:可以,你什么时候发?
主机A:我马上发,你接着!
经过三次对话之后,主机A才会向主机B发送正式数据,而UDP是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发过去了。所以 TCP 能够保证数据包在传输过程中不被丢失,但美好的事物必然是要付出代价的,相比 UDP,TCP 实现过程复杂,消耗连接资源多,传输速度慢。
TCP 数据包和 UDP 一样,都是由首部和数据两部分组成,唯一不同的是,TCP 数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常 TCP 数据包的长度不会超过IP数据包的长度,以确保单个 TCP 数据包不必再分割。
总结一下,传输层的主要工作是定义端口,标识应用程序身份,实现端口到端口的通信,TCP协议可以保证数据传输的可靠性。
4、应用层
理论上讲,有了以上三层协议的支持,数据已经可以从一个主机上的应用程序传输到另一台主机的应用程序了,但此时传过来的数据是字节流,不能很好的被程序识别,操作性差。因此,应用层定义了各种各样的协议来规范数据格式,常见的有 HTTP、FTP、SMTP 等,HTTP 是一种比较常用的应用层协议,主要用于B/S架构之间的数据通信,其报文格式如下:
在 Resquest Headers 中,Accept 表示客户端期望接收的数据格式,而 ContentType 则表示客户端发送的数据格式;在 Response Headers 中,ContentType 表示服务端响应的数据格式,这里定义的格式,一般是和 Resquest Headers 中 Accept 定义的格式是一致的。
有了这个规范以后,服务端收到请求以后,就能正确的解析客户端发来的数据,当请求处理完以后,再按照客户端要求的格式返回,客户端收到结果后,按照服务端返回的格式进行解析。
所以应用层的主要工作就是定义数据格式并按照对应的格式解读数据。
5、全流程
首先我们梳理一下每层模型的职责:
- 链路层:对0和1进行分组,定义数据帧,确认主机的物理地址,传输数据;
- 网络层:定义IP地址,确认主机所在的网络位置,并通过IP进行MAC寻址,对外网数据包进行路由转发;
- 传输层:定义端口,确认主机上应用程序的身份,并将数据包交给对应的应用程序;
- 应用层:定义数据格式,并按照对应的格式解读数据。
然后再把每层模型的职责串联起来,用一句通俗易懂的话讲就是:
当你输入一个网址并按下回车键的时候,首先,应用层协议对该请求包做了格式定义;紧接着传输层协议加上了双方的端口号,确认了双方通信的应用程序;然后网络协议加上了双方的IP地址,确认了双方的网络位置;最后链路层协议加上了双方的MAC地址,确认了双方的物理位置,同时将数据进行分组,形成数据帧,采用广播方式,通过传输介质发送给对方主机。而对于不同网段,该数据包首先会转发给网关路由器,经过多次转发后,最终被发送到目标主机。目标机接收到数据包后,采用对应的协议,对帧数据进行组装,然后再通过一层一层的协议进行解析,最终被应用层的协议解析并交给服务器处理。
6、总结
以上内容是对TCP/IP四层模型做了简单的介绍,而实际上每一层模型都有很多协议,每个协议要做的事情也很多,但我们首先得有一个清晰的脉络结构,掌握每一层模型最基本的作用,然后再去丰富细枝末节的东西,也许会更容易理解。
参考资料:
https://www.cnblogs.com/onepixel/p/7092302.html
TCP 3次握手和4次挥手
TCP建立连接为什么是三次握手,而不是两次或四次?
TCP,名为传输控制协议,是一种可靠的传输层协议,IP协议号为6。
顺便说一句,原则上任何数据传输都无法确保绝对可靠,三次握手只是确保可靠的基本需要。
举个日常例子,打电话时我们对话如下:
对应为客户端与服务器之间的通信:
于是有了如下对话:
我:1+1等于几?
她:2,2+2等于几?
我:4
首先两个人约定协议
1.感觉网络情况不对的时候,任何一方都可以发起询问
2.任何情况下,若发起询问后5秒还没收到回复,则认为网络不通
3.网络不通的情况下等1min路由器之后再发起询问
对于我而言,发起 “1+1等于几”的询问后
1. 若5s内没有收到回复,则认为网络不通
2. 若收到回复,则我确认①我能听到她的消息 ②她能听到我的消息,然后回复她的问题的答案
对于她而言,当感觉网络情况不对的时候
1. 若没有收到我的询问,则她发起询问
2. 若收到“1+1等于几”,则她确认 ①她可以听到我的消息,然后回复我的问题的答案和她的问题“2,2+2等于几”
3. 若5s内没有收到我的回复“4”,则她确认 ②我听不见她的消息
4. 若5s内收到了我的回复“4”,则她确认 ②我可以听见她的消息
这样,如果上面的对话得以完成,就证明双方都可以确认自己可以听到对方的声音,对方也可以听到自己的声音!
这个故事可以解释TCP为什么要三次握手吗 ... 囧
关于四次挥手
先由客户端向服务器端发送一个FIN,请求关闭数据传输。
当服务器接收到客户端的FIN时,向客户端发送一个ACK,其中ack的值等于FIN+SEQ
然后服务器向客户端发送一个FIN,告诉客户端应用程序关闭。
当客户端收到服务器端的FIN是,回复一个ACK给服务器端。其中ack的值等于FIN+SEQ
为什么要4次挥手?
确保数据能够完整传输。
当被动方收到主动方的FIN报文通知时,它仅仅表示主动方没有数据再发送给被动方了。
但未必被动方所有的数据都完整的发送给了主动方,所以被动方不会马上关闭SOCKET,它可能还需要发送一些数据给主动方后,
再发送FIN报文给主动方,告诉主动方同意关闭连接,所以这里的ACK报文和FIN报文多数情况下都是分开发送的。
一、TCP报文格式
TCP报文格式图:
上图中有几个字段需要重点介绍下:
(1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
(3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
(A)URG:紧急指针(urgent pointer)有效。
(B)ACK:确认序号有效。
(C)PSH:接收方应该尽快将这个报文交给应用层。
(D)RST:重置连接。
(E)SYN:发起一个新连接。
(F)FIN:释放一个连接。
需要注意的是:
(A)不要将确认序号Ack与标志位中的ACK搞混了。
(B)确认方Ack=发起方Req+1,两端配对。
二、三次握手
TCP(Transmission Control Protocol) 传输控制协议
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接
位码即tcp标志位,有6种标示:
SYN(synchronous建立联机)
ACK(acknowledgement 确认)
PSH(push传送)
FIN(finish结束)
RST(reset重置)
URG(urgent紧急)
Sequence number(顺序号码)
Acknowledge number(确认号码)
establish 建立,创建
所谓三次握手(Three-Way Handshake)即建立TCP连接,是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:
(1)第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
(2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack (number )=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
(3)第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
SYN攻击:
在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:
#netstat -nap | grep SYN_RECV
三、四次挥手
三次握手耳熟能详,四次挥手估计就..所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示:
由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。
(1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
(2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
(3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
(4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
上面是一方主动关闭,另一方被动关闭的情况,实际中还会出现同时发起主动关闭的情况,具体流程如下图:
流程和状态在上图中已经很明了了,在此不再赘述,可以参考前面的四次挥手解析步骤。
四、附注
关于三次握手与四次挥手通常都会有典型的面试题,在此提出供有需求的XDJM们参考:
(1)三次握手是什么或者流程?四次握手呢?答案前面分析就是。
(2)为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
参考资料:https://www.cnblogs.com/lms0755/p/9053119.html