网络协议模型
1.OSI 七层模型
OSI 采用了分层的结构化技术,共分七层,物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
2.TCP/IP 模型
OSI 模型比较复杂且学术化,所以我们实际使用的 TCP/IP 模型(总共是5层)。
物理层、数据链路层(也有 TCP/IP 模型将物理层、数据链路层合称为网络接口层,与之对应的,协议就被称为 TCP/IP 四层协议模型)、网络层、传输层、应用层。
TCP/IP模型应用层相当于把OSI模型会话层、表示层、应用层合在一起。
对于我们的 PC 机来说,物理层可以看成网卡,数据链路层可以看成网卡驱动程序,网络层
和传输层由操作系统负责处理,应用层则是常用的一些网络应用程序和我们自己所编写的网
络应用程序。
IP:用于确定网络中唯一的一台计算设备
TCP/UDP:传输层主要为两台主机上的应用程序提供端到端的通信
我们一些常见的网络应用基本上都是基于 TCP 和 UDP 的,这两个协议又会使用网络层的IP 协议。
我们可以绕过传输层的 TCP 和 UDP,直接使用 IP,比如 Linux 内核中的LVS 就可以直接基于 IP 层进行负载平衡调度;甚至还可以直接访问链路层,比如 tcpdump程序就是直接和链路层进行通信的。
TCP/IP 网络传输中的数据:
下层协议数据包含了上层数据。
数据包是一个统称,每一层的叫法不同。
地址和端口号:
MAC 地址(物理层):全称叫做媒体访问控制地址(Media Access Control),也称为局域网地址(LAN Address),MAC 位址,以太网地址(Ethernet Address)或物理地址(Physical Address)。MAC 地址与网络无关,它由厂商写在网卡的 BIOS(硬件内部) 里。一般来说,当一台 PC 机的网卡坏了之后,更换了网卡之后 MAC 地址就会变。
IP 地址(网络层):全称叫作互联网协议地址,基于逻辑,比较灵活,不受硬件限制,也容易记忆。
IP 地址的分配是基于我们自身定义的网络拓扑,MAC 地址的分配是基于制造商。
IP 地址的长度为 32 位,而MAC 地址为 48 位。
公网ip和内网ip有谁分配?
内网ip通常由路由器或网络设备分配,或个人动态配置。
公网ip由互联网服务提供商ISP分配。ISP会从一个较大的IP地址池中获得一定数量的公网IP地址,然后将这些IP地址分配给其客户。这些IP地址可以用于连接到互联网的各种设备,如家庭路由器、企业服务器等。
端口号(传输层):在传输层,用来识别同一台计算机中进行通信的不同应用程序,决定数据传给哪个应用程序。
为什么端口号有 65535 个?
因为在 TCP、UDP 协议报文的开头,会分别各有 16 位二进制来存储源端口号和目标端口号,所以端口个数是 2^16=65536 个,但是 0 号端口用来表示所有端口,所以实际可用的端口号是 65535 个。
端口号的确定:
1.知名端口号:固定端口号,例如 HTTP、FTP、TELNET使用的端口号就是固定的。分布在 0~1023 之间。
2.时序分配法:交给操作系统进行分配。
操作系统是通过源 IP 地址、目标 IP 地址、协议号(协议类型)、源端口号以及目标端口号这五个元素唯一性的识别一个网络上的通信(连接)。
一台主机上只能保持最多 65535 个 TCP 连接,对吗?
远远不止。
这个说法不对,我们分服务器和客户端分开讨论,以下的讨论都基于服务器和客户端都只有 1 个 IP 地址。
服务端:(理论上,我们每个 server 可以接收的连接上限就是两百多万亿)。
拿我们常用的 MySQL 举例,假设它的 IP 是 X,端口 3306。用户 A 基于 IP 地址 A1,端口PA 连接 MySQL ,于是构成了一个 TCP 连接四元组(A1,PA,X,3306)
用户 B 基于 IP 地址 B1,端口 PB 连接同一个 MySQL,这个时候 MySQL 需要开启一个新端口来和用户 B 通信吗?从我们日常的开发就可以知道,MySQL 并不需要这么做,所以用户 B 就和 MySQL 构成了一个新的 TCP 连接四元组(B1,PB,X,3306)。
(A1,PA,X,3306)
(B1,PB,X,3306)
A1*PA=2 的 32 次方(ip 数)× 2的 16 次方(port 数)=大约等于两百多万亿。(IP 地址的长度为 32 位)
当然实际上做不到,目前工程实践中可以达到的连接数在千万级别。
客户端:
前面我们已经说过,“客户端应用程序完全可以不用自己设置端口号,而全权交给操作系统进行分配”,可用的端口号只有 6 万多,从这个角度考虑,客户端最多只能发起 6 万多条 TCP 连接。但其实也不是。
“源 IP 地址、目标 IP 地址、源端口号以及目标端口号才能唯一性确定一个 TCP 连接”。
对客户端来说,四元组里有 3 个可变(源端口、目的 IP 地址和目的端口),客户端能同时支持的连接数为3 个可变的笛卡尔积,所以客户端能支持的连接数远大于65535。他能同时支持的连接数比服务器还要大得多。
所以一般来说,不管计算机中有多少网卡,每个网卡都会有自己的 MAC 地址,这个MAC 地址是不会变化的。而每个网卡在正常工作的情况下,都会有一个 IP 地址,这个 IP地址完全是可以变化的。而这台计算机中承载的各种应用程序可以拥有自己的端口号,然后通过服务器的网卡,正确地进行网络通信。
一台服务器上的不同网络应用程序必须有不同的端口号,A 程序启动了使用了端口 x,B 程序启动就不能使用端口 x,否则会报错“Address already in use”。
总的来说,操作系统是通过源 IP 地址、目标 IP 地址、协议号(协议类型)、源端口号以及目标端口号这五个元素唯一性的识别一个网络上的通信。
TCP 特性:
在我们上面的讲述中,存在着客户端和服务端两者角色,在网络通信里是怎么区分客户端和服务端的?
这个就牵涉到了 TCP 的相关特性。 TCP(Transmission Control Protocol)是面向连接的通信协议,通过三次握手建立连接, 然后才能开始数据的读写,通讯完成时要拆除连接,由于 TCP 是面向连接的所以只能用于端 到端的通讯。
全双工:允许在一个 TCP 连接上,通信的双方可以同时传输数据。
TCP提供的是一种可靠的数据流服务,数据有可能被拆分后发送,那么采用超时重传机制和应答确认机制是组成TCP可靠传输的关键设计。
超时重传机制怎样才算超时(RTO),需要涉及到RTT,即估算每次报文来回时间来动态设置超时时间RTT(重传超时时间)。
IP层无法保证包的顺序,TCP层会对包进行排序,对损坏的包进行重传。
流量控制:TCP 还采用一种称为“滑动窗口”的方式进行流量控制,用以限制发送方的发送速度,控制每次发送报文的大小,因为两端每次能接收的数据是有限制的,传多也没用。
序列号(seq_no):可以借助传输序列号,来告诉对方你的包我收到了,然后你要从哪个序列号开始发送数据给我。
面向连接的服务(例如 Telnet、FTP、rlogin、X Windows 和 SMTP)需要高度的可靠性,所以它们使用了 TCP。DNS 在某些情况下使用 TCP(发送和接收域名数据库),但使用 UDP传送有关单个主机的信息。
TCP 三次握手
TCP 提供面向有连接的通信传输。面向有连接是指在数据通信开始之前先做好两端之间
的准备工作(先连接)。
所谓三次握手是指建立一个 TCP 连接时需要客户端和服务器端总共发送三个包以确认连接的建立。在 socket 编程中,这一过程由客户端执行 connect 来触发,所以网络通信中,发起连接的一方我们称为客户端,接收连接的一方我们称之为服务端。
简易速记版
但是简易速记版,在真实的面试中不能让面试官满意,很多公司还会考察握手过程中的
具体详情:
SYN:同步序列编号(Synchronize Sequence Numbers)
ACK为一个标识位,ack为ack_no字段,两个不一样。
第一次握手:客户端将请求报文标志位 SYN 置为 1,请求报文的 Sequence Number 字段
(简称 seq)中填入一个随机值 J,并将该数据包发送给服务器端,客户端进入 SYN_SENT 状
态,等待服务器端确认。
第二次握手:服务器端收到数据包后由请求报文标志位 SYN=1 知道客户端请求建立连
接,服务器端将应答报文标志位 SYN 和 ACK 都置为 1,应答报文的 Acknowledgment Number
字段(简称 ack)中填入 ack=J+1,应答报文的 seq 中填入一个随机值 K,并将该数据包发送
给客户端以确认连接请求,服务器端进入 SYN_RCVD 状态。
第三次握手:客户端收到应答报文后,检查 ack 是否为 J+1,ACK 是否为 1,如果正确
则将第三个报文标志位 ACK 置为 1,ack=K+1,并将该数据包发送给服务器端,服务器端检
查 ack 是否为 K+1,ACK 是否为 1,如果正确则连接建立成功,客户端和服务器端进入
ESTABLISHED 状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
第三次握手是用于告诉服务端已经收到了你的确认,并且告知服务端已经收到了哪个位置的数据,让服务端下次从哪个位置发送数据。
为什么 TCP 握手需要三次?
三次是最少的。三次握手是保证数据可靠传输又能提高传输效率的最小次数。
TCP 的三次握手的漏洞-SYN 洪泛攻击(ddos攻击的一种)
三次握手中有一个第二次握手,服务端向客户端应答请求,应答请求是需要客户端 IP 的,而且因为握手过程没有完成,操作系统需要使用队列来存储这个状态,直到三次握手成功后才会删除。
攻击者通过伪造大量伪造这个IP地址,且这个IP地址是不可访问的,这样服务端每次向客户端应答请求时候,每次都不成功,这样当伪造大量请求的时候,队列就满了,从而就会拒绝其它连接。这就是洪泛攻击。
面对这种攻击,有以下的解决方案,最好的方案是防火墙。
防火墙在确认了连接的有效性后,才向内部的服务器(Listener)发起 SYN 请求。
TCP 四次挥手(分手)
四次挥手即终止 TCP 连接,就是指断开一个 TCP 连接时,需要客户端和服务端总共发
送 4 个包以确认连接的断开。在 socket 编程中,这一过程由客户端或服务端任一方执行 close
来触发。
(1)某个应用进程首先调用 close,我们称该端执行主动关闭(active close)。该端的 TCP
于是发送一个 FIN 分节,表示数据发送完毕,应用进程进入 FIN-WAIT-1(终止等待 1)状态。
(2)接收到这个 FIN 的对端执行被动关闭(passive close),发出确认报文。因为客户端发送的 FIN 的接收意味着接收端应用进程在相应连接上再无额外数据可接收(客户端不在发送数据),接收端进入了 CLOSE-WAIT(关闭等待)状态,这时候处于半关闭状态,即主动关闭端已经没有数据要发送了,但是被动关闭端若发送数据,主动关闭端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT 状态持续的时间。主动关闭端收到确认报文后进入 FIN-WAIT-2(终止等待 2)状态。
(3)一段时间后,被动关闭的应用进程将调用 close 关闭它的套接字。这导致它的 TCP 也发送一个 FIN,表示它也没数据需要发送了。
(4)接收这个最终 FIN 的原发送端 TCP(即执行主动关闭的那一端)确认这个 FIN 后发出一个确认 ACK 报文,并进入了 TIME-WAIT(时间等待)状态。注意此时 TCP 连接还没有释放,
必须经过 2∗MSL((Maximum Segment Lifetime)报文最长存活时间)的时间后,当主动关闭端撤销相应的 TCB 后,才进入 CLOSED 状态。
所以主动关闭端为什么没有立即关闭连接,而是要等待2*MSL?是因为要撤销相应的 TCB,即释放完资源后才关闭。
TCB指的是传输控制块,用来管理每一个TCP连接的数据结构。TCB包含了与该TCP连接相关的各种信息,包括连接的状态、发送和接收窗口大小、序列号、确认号等。通过管理TCB,操作系统可以对TCP连接进行有效的控制和管理。
当主动关闭端发出最后的ACK后,会撤销相应的TCB,表示该TCP连接已经结束。
(5) 被动关闭端只要收到了客户端发出的确认,立即进入 CLOSED 状态。同样,撤销 TCB后,就结束了这次的 TCP 连接。可以看到,被动关闭端结束 TCP 连接的时间要比主动关闭端早一些。(为什么被动关闭端不需进入TIME-WAIT状态?因为此时服务端已经没有数据要发送了)
既然每个方向都需要一个 FIN 和一个 ACK,因此通常需要 4 个分节。我们使用限定词“通常”是因为:某些情形下步骤 1 的 FIN 随数据一起发送;另外,步骤 2 和步骤 3 发送的分节都出自执行被动关闭那-一端,有可能被合并成一个分节。
为什么 TCP 的挥手需要四次?
(最少4次才能确保两端都关闭了连接)
TCP 是全双工的连接,必须确认两端都关闭了连接,连接才算真正关闭。
主动方关闭写,被动方关闭读,被动方关闭写,主动方关闭读总共4次挥手。
UDP 和 UDT、QUIC
UDP(User Datagram Protocol 的简称, 中文名是用户数据报协议)
是把数据直接发出去,而不管对方是不是在接收,也不管对方是否能接收的了,也不需要接收方确认,属于不可靠的传输,可能会出现丢包现象,实际应用中要求程序员编程验证。
udp协议和需要建立连接吗?
不需要。
UDP 单播和广播
单播模式:发送消息给单一目的地。
广播模式:传输到网络(或者子网)上的所有主机。由于通讯不需要连接,所以可以实现广播发送。广播可以不需要指定IP和端口,所有在该网络的人都可以收到信息,能不能收到可以设置广播类型来设置。
使用 UDP 的服务包括
1.NTP(网络时间协议)和 DNS(DNS 也使用 TCP),包总量较少的通信(DNS、SNMP 等);
2.视频、音频等多媒体通信(即时通信);
3.限定于 LAN 等特定网络中的应用通信;
4.DHCP 等协议就利用了 UDP 的广播功能。
常用的 QQ,就是一个以 UDP 为主,TCP 为辅的通讯协议。
udp丢包情况
1.TCP/IP每一个报文里面包含跳数,当报文每经过一个路由器,跳数-1,如果跳数变为0,则报文会被丢弃。为了防止IP数据报永久兜圈,当路由器由于各种原因丢弃IP数据报时,就会发送ICMP差错报告报文给源点主机。。
2.路由器会先缓存报文再解析每个报文目的地然后再发送到对应地址。如果缓存满了就丢弃之后加进来的报文。