前言

TCP/IP 协定 是网络通信的基石,TCP/IP 协定 不是只有 TCPIP 协定,它是整个网络通信中所有协定的简称。

维基百科:TCP/IP协定簇)

维基百科:OSI模型

# TCP/IP 参考模型维基百科https://zh.wikipedia.org/wiki/TCP/IP%E5%8D%8F%E8%AE%AE%E6%97%8F# OIS 参考模型维基百科https://zh.wikipedia.org/wiki/OSI%E6%A8%A1%E5%9E%8B

<img src="http://oss.mflyyou.cn/blog/20200801104517.png?author=zhangpanqin" alt="image-20200801104517510" style="zoom:50%;" />

图片来自 《图解 TCP/IP 与 OSI 参考模型》 中 TCP/IP 协定分层模型

OSI 参考模型 (七层)是个实践模型,理论咱们用的是 TCP/IP (四层)模型。不过咱们能够通过 OSI 参考模型 来学习 TCP/IP 模型。

应用层:应用程序通信细节的协定,比方罕用的 HTTP

传输层:次要是负责两个节点之间数据传输,通信标识是 port 端口号。

网络层:地址治理和路由抉择,在两点之间找到一条最佳的通信路线,通信标识是 IP

数据链路层:负责物理层面链接的通信(同一个网段内)。也就是局域网中通过交换机链接的节点。通信标识是 Mac 地址,网卡出厂自带的标识。

物理层:将链路层的数据帧(字节流)转换为电压或光信号流传。

网络通信能够做什么呢?

redisson (一个操作 redis 的 java 库),就是应用的 netty 来做网络通信连贯 redis 服务的。

微服务中的服务发现和通信,就须要你相熟网络通信。

你要是在通信行业,那就不是理解了,你连协定的标准都得很分明,不然路由器你都整不进去,还说什么 5G

作为一个 Java 后端开发,次要是开发偏利用层面的程序,离底层绝对比拟远,熟练掌握即可,如果当前做通信行业的时候,你也肯定会进一步学习的相干细节的。

TCP/IP 你不理解,也不会有多大问题,CRUD 还是没有问题的。然而你理解了之后,日常开发定位和解决问题方面有很大助力,总之学习 TCP/IP 是一个重要不紧急的事件,依据本人指标和档次安顿。

本文内容

  • 局域网中各节点怎么通信
  • 介绍 IP,ICMP,ARP 协定在网络层的作用及路由表的作用,及网段划分,子网掩码、网关的作用
  • 介绍交换机和路由器的作用
  • 介绍 TCP/IP 三次握手和四次挥手,TCP 中通信状态的作用,滑动窗口
  • 介绍 tcp 包格局,ip 包格局,链路层 数据格式

交换机与路由器

交换机

维基百科:交换机)

交换机上有多个端口(不是 port)供计算机连贯,替换机会保护端口与连贯这个端口的 PC 的 Mac 地址映射表。当交换机承受到数据的时候,会依据目标 Mac 地址,发送到对应的端口上,而后通过网线发送到目标 PC。

交换机链接多个电脑组成一个局域网,交换机链接交换机又能够组成一个更大的局域网。

比方 A、B 交换机各有 100 个端口,A 链接了 99 个PC,而后 B 交换机链接99 个,再将其中的一个端口 A/B 之间相互连接组成一个更大的局域网。

路由器

维基百科:路由器)

路由器工作在网络层,次要用于将一个网段数据包转发到另一个网段内。路由器上也会有个几个 LAN 口 (Local Area Network,局域网),用于建设局域网。还会有一个 WAN(Wide Area Network,广域网),连贯运营商的网络。

路由器也具备交换机的性能,只是 LAN 口 比拟少,能够接入的电脑比拟少。

PC 或者 手机 连贯无线路由器时也会给 PC 调配一个局域网 IP,子网掩码,网关等。

我住的中央的网络拓扑图如下:

当手机与电脑通信的时候,理论通过 LAN 口走局域网通信。

当手机拜访 维基百科 时,理论是通过路由器跳入到光猫网段,再通过光猫跳入到小区运营商的网络,… 到维基百科的服务器上。

只有须要有 IP 地址的设施(光猫,路由器,PC,手机)都须要有网卡,网卡出厂自带有 Mac 地址。IP 和 Mac 地址的作用后文中会介绍。

交互机和路由器的区别

<font color=red>这部分内容是我本人的了解,我没有在网上找到材料佐证,请审慎看待</font>

其实交换机和路由器硬件差异不大,只是硬件上的软件决定了它能做什么。

2 层交换机上的软件(只有数据链路层)可能只做解析帧,拿到 mac 地址,而后查找以后交换机的端口对应的 mac 地址,而后从对应的端口传递过来。

路由器(有网络层和数据链路层),当拿到数据包的时候,发现目标 mac 地址不是本人,就会将数据包通过 LAN 口发送进来。

当发送的数据包的 目标 MAC 地址 是以后路由器上 MAC地址 ,路由器就会对其解包,拿到数据包 目标 IP ,而后依据 目标 IP 匹配下一跳 mac 地址,封包为新的帧数据发送进来。

TCP/IP 通信

从发送端发送数据的时候,数据通过每层的封包,经物理层传送到接收端。接收端收到数据包,一层一层进行拆包,而后将数据数据发送给我接收端的应用层的应用程序。

通常咱们说的第一层就是 物理层 ,第二层是 链路层 …...

数据链路层

源 MAC 地址 就是发送端的 MAC 地址,指标 MAC 地址不是最终的 MAC 地址,是下一跳节点的 MAC 地址。

类型 指的是这个以太网帧中的 数据 是何种类型的数据,比方 IPV4,IPV6。而后调用对应的接口进行解决。

数据链路层传输的帧是有大小限度的(64-1518 字节),能传输的数据的最大值就是 最大传输单元,简称 MTUMaximum Transmission Unit。这个值在以太网中通常是 1500。

# 查看网卡对应的 MTUifconfig -anetstat -i

网络层

网络层次要以 IP 协定为主,也有 ICMP,ARP(在 TCP\IP 模型 中,arp 属于网络层。在 osi 七层模型arp 数据链路层。)。

DNS

IP 是网络层通信的标识。然而 IP 不容易记忆,所以呈现了 域名

拜访 DNS 能够将域名解析为 IP

能够在本地配置 host ,定义域名和 IP 对应关系,这样就不必解析了。

也能够在电脑配置 DNS 解析时拜访的 ip,这样域名解析时就会拜访这个服务。

<img src="http://oss.mflyyou.cn/blog/20200801182357.png?author=zhangpanqin" alt="image-20200801182357581" style="zoom:50%;" />

# 解析域名的 ipdig www.mflyyou.cn

IP 根底

IP 地址 又能够分为 IPV4IPV6,目前应用比拟广的是 IPV4 ,所以只介绍 IPV4

IP 地址 由 32 (2 进制)位组成,32 位被 . 分为了四组。每组 8 位,十进制示意就是 xxx.xxx.xxx.xxx(xxx 取值在 0-255)。

IP 地址网络地址 (网段) 和 主机号

同一个网段的电脑用 2 层交互机相连,而后就能够局域网通信了。

同一个网段内,主机号不能反复,反复主机号的电脑不能上网。

为了便于辨别出 IP 在那个网段,引入了子网掩码 (netmask)。IP 地址与子网掩码按位与计算能够得出网段,32 位 中取出网段所在的位,残余就是主机号能获得值。

IP 中主机号全为 0 就是网段,全为 1 就是播送地址。这两个是不能被调配给电脑的。

IP:192.168.202.116

子网掩码:255.255.252.0

网段为:192.168.200.0

播送地址为:192.168.203.255

IP:192.168.201.56

子网掩码:255.255.252.0

网段为:192.168.200.0

播送地址为:192.168.203.255

ICMP

网络层是不牢靠传输,发送失败的数据包,网络层是不会再发一次数据包,然而会有 ICMP 包回复通知你发包到底是什么问题。传输层 能够依据 ICMP 来判断是否须要重发包。

ARP

ARP 用于 IP 的 对应的MAC 地址。

目标 IP 在路由表中查问下一跳的 IP,在查问这个 IP 对应的 mac 地址

查问的这个 IP 是以后网段内的 ip,它会通过播送地址发送给以后网段内所有主机,收到这个协定的主机会判断是否是以后主机,是的话就会复原以后 ip 对应的 MAC 地址。

通信过程剖析

当我在浏览器输出 wwww.mflyyou.cn 的时候:

1、先解析域名(DNS) www.mflyyou.cnIP (目标 IP: 47.104.168.20)

2、将目标 IP 与本地路由表中的子网掩码进行按位与,计算出网段与 Destination 匹配,看哪个匹配度更高,走哪个条目。都没有匹配到走默认条目(0.0.0.0)

# 查看路由表route -n
Kernel IP routing tableDestination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         192.168.31.1    0.0.0.0         UG    100    0        0 eth0

3、而后用 arp 查问(有缓存可不查,走缓存)192.168.31.1 对应的 mac 地址

4、数据链路层封装以太网帧数据包中的目标 MAC 地址址就是 192.168.31.1 对应的 mac 地址,而后将数据帧发送到下一个节点(这也就常说的下一跳,数据包发送只是找到以后接节点的下一个节点)

5、到下一个路由器节点,路由器解包,看是发给本人的数据包(依据帧中的目标 MAC 地址与本人的 MAC 地址比拟),不是就抛弃了;是的话就会解包拿到 目标 IP (47.104.168.20),而后在以后路由器上依据路由表查问下一跳,发送给下一个节点;。。。。 直到目标服务器,或者发送的包 TTL 为 0

6、发到目标服务器的网卡上,网卡将数据复制到内核缓冲区,应用程序从缓冲区中读取数据

IP 数据格式

<font color=red>IPv4 数据结构</font>

<img src="http://oss.mflyyou.cn/blog/20200802000153.png?author=zhangpanqin" alt="image-20200802000153692" style="zoom:50%;" />

图来自《图解 TCP/IP》
  • 版本(Version):4 bit 形成,代表以后 IP包是哪个版本,IPv4 或者 IPv6,为 4 时示意以后是 IPv4。
  • 首部长度(Internet Header Length):由 4 bit 形成,个别 20字节大小。
  • 标识(Identification):用于分片重组用,值雷同的属于同一个 IP 数据包
  • 标记(Flags):用于判断是否还有分片。
  • 总长度(Total Length):16 个字节,IP 数据包总的长度,最长可为 65525 字节。
  • 分段偏移(Fragment Offset):示意这个包在原来 IP 包中的地位。
  • 生存工夫 TTL(Time To Live): IP 包在路由转发中存活的工夫,被路由转发一次,次数减 1,为 0 时,数据包被抛弃。
  • 挂载协定标识 (Protocol):记录数据包中 Data(理论发送的数据)是什么类型的数据,1 标识 ICMP, 4 标识 IP, 6标识 TCP, 17 标识 UDP。依据这个挂载协定程序就晓得调用哪些接口来进行后续的解决了。

数据链路层中 以太网数据帧MTU 是 1500 字节,限定了 IP 数据包最大为 1500 字节。而后去掉 IP 包首部 20 字节,个别 IP 数据包发送的数据为 1480 字节。

当咱们发送一个 3058 字节的 IP 数据包时,这显然大于了数据链路层的 MTU (1500 字节)。所以网络层会对大于链路层MTU 的数据包进行分片。拆分一个一个的1500 的数据包发送接收端,接收端接管到这三个包,在汇聚成一个实现的,在调用传输层接口。

# 会发送 3050 字节数据与 8 字节的 ICMP 首部,这个命令会总共发送 ip 数据大小 3058 字节。ping -s 3050 www.mflyyou.cn

<img src="http://oss.mflyyou.cn/blog/20200801230141.png?author=zhangpanqin" alt="image-20200801230141070" style="zoom:50%;" />

<img src="http://oss.mflyyou.cn/blog/20200801230528.png?author=zhangpanqin" alt="image-20200801230528418" style="zoom:50%;" />

<img src="http://oss.mflyyou.cn/blog/20200801230423.png?author=zhangpanqin" alt="image-20200801230423653" style="zoom:50%;" />

通过 wireshark 抓包能够看到,IP 数据包的首部长度占了 20 字节,理论每次发送数据为 1480 字节,最初一次发送了 98 字节。

从 Fragment 和 Identification 能够看到这三个包属于同一个 IP 数据包,并且从 Fragment offset 能将这三个包合成一个实现的网络层数据包。

传输层 TCP

TCP 是面向链接的,牢靠的,全双工协定。

面向连贯就是发送之前,须要建设一个链接通道,数据都是在这个链接中发送。

网络层 是不牢靠协定,数据发送失败是不会重发的。

TCP 协定中发送端会记录发送的那些数据包被客户端收到了。接收端承受数据之后,会回复一个 ACK 包(由数据格式中的管制位决定),确认应答号通知发送端哪些数据包接管到了。

发送端 发送了数据包之后,这个包会有一个重发倒计时,在这个倒计时内没有收到接收端 回复 ACK 包,就会再重发一个数据包。如果是 HTTP 申请 ,就相当于同样的数据申请了两次。

咱们晓得领取接口都要求幂等性,有一部分起因是因为这个超时重发。发送端发送了申请,接收端解决好业务之后回复的 ACK 包超时,发送端超时重发这个申请。如果不保障接口的幂等性,那么扣钱就会扣两次。

咱们要做的就是保障这个重发 n+1 次不再扣用户的钱,个别会用一个 token 来判断是不是反复申请,反复就不走扣款解决了,间接返回曾经领取,保障接口的幂等性。或者用一个账单流水来保障幂等性。

连贯既然须要建设,那么也会有连贯断开。断开连接需单方协商好之后断开连接,不能单方面敞开而不论对方。因为建设连贯之后占用的计算机资源须要开释掉。你单方面强制断开连接开释了资源,然而对方不晓得须要断开连接,调配的计算机资源始终占用那就是不牢靠协定了。所以 TCP 有四次挥手断开连接。

全双工就是连贯两边都能够被动发送承受数据,而不是轮训拜访有没有数据达到。

TCP 数据格式

首先咱们要先理解 TCP 数据格式,能力更容易晓得 TCP 的工作原理。

<img src="http://oss.mflyyou.cn/blog/20200802000246.png?author=zhangpanqin" alt="image-20200802000246545" style="zoom:50%;" />

源端口号(Source Port)

占用 2 个字节。标识 发送端 程序的端口号,当接收端须要回复音讯的时候,须要带上这个端口号。

目标端口号(Destination Port)

占用 2 个字节。标识 接收端 程序的端口号,能够传递给监听在这个端口的程序

管制位(Control Flag)

占用 6 位,不满一个字节。标识以后 TCP 包是什么包,在通信过程中有一些特殊作用。

SYN

示意心愿建设三次握手链接,并初始化序列号。

ACK

对收到数据包的应答确认。接收端承受数据之后,会回复 ACK 包,发送端从其上 确认应答号 晓得接收端哪些数据曾经承受了。

FIN

示意没有数据发送了,心愿断开连接

PASH

接收端接管到这个数据包须要立即传递给应用层,不能期待接管更多的数据包

RET

链接出现异常,须要强制断开连接

URG

示意包中有须要紧急解决的数据

序列号(Sequence Number)

占用 4 个字节。TCP 三次握手的时候,发送端和接收端各自初始化(随机的)本人的 `序列号。

咱们能够这样了解,发送端发送的数据就是一个字节数组,这个数组中每个字节都有一个 序列号

发送端和接收端都有本人的序列号,并且不雷同,在三次握手的时候本人初始化,而后告知对方。

确认应答号(Acknowledgement Number)

占用 4 个字节。确认应答号 也是指的序列号,指的是冀望发送端下次发送的序列号,这个序列号(确认应答号)之前的数据曾经承受解决了。

下图是我抓包建设三次链接,而后我发送三次 1\n 数据。

三次握手,发送端通过发送 SYN 包,发送本人的初始化序列号(893189542),而后发送的每个字节都会有一个序列号。

接收端发送 ACK 包中的 确认应答号,指明这个序列号之前的数据我曾经承受了。

<img src="http://oss.mflyyou.cn/blog/20200802205000.png?author=zhangpanqin" alt="image-20200802205000890" style="zoom:50%;" />

窗口大小(Window Size)

窗口大小实用于流控的。发送端不能始终发送音讯,须要依据我的承受能力来调整发包的速率。

内核会为每个 TCP/IP 调配读写缓冲区,网卡会从这些读写缓冲区中把数据取走,而后发送。数据大抵能够分为这几类。

TCP/IP 是牢靠连贯,所以它须要记录哪些数据发送已被对方承受了(由确认应答号能够晓得),承受的数据会被淘汰掉,节俭内存空间。

窗口大小作用:接收端会通过 ACK 通知 发送端 调整窗口大小。

当窗口中的数据全都是 已发送未确认数据 时,发送端不能再发送新的数据,必须期待窗口空出地位来。

当有一个数据包被确认了,发送端就能够发送新的数据包。已发送未确认数据 会在超时的时候从新发包。

滑动窗口百度百科)

校验和 (Checksum)

占用 2 个字节。校验和 用于校验数据包是否损坏。每个数据包都一个 校验和接收端 接管到数据之后,应用雷同的算法对数据计算出一个值,而后和 校验和比拟,不一样阐明数据在传输过程中损坏了,接收端 会抛弃这个包,期待 发送端 从新发这个包。

TCP 中 MSS

链路层能发送的最大以太网帧为 1500 字节,MTU 为 1500。

IP 数据包能发送的最大数据 = MTU - IP 首部大小(个别 20 字节),IP 数据包超过这个 1500 字节会分片

TCP 传输数据以段 (Segment) 为单位。

TCP 为了防止分片,会被动将数据分片之后交给网络层。 TCP 能传输的最大分段(只是数据不包含首部)称之为 Max Segment Size,简称为 MSS。

MSS = MTU - IP 首部大小 - TCP 首部大小

在以太网中 TCP 的 MSS = 1500(MTU) - 20(个别 IP 首部大小) - 20(个别 TCP 首部大小)= 1460,这个值须要依据首部计算

MSS 值在三次握手时,会通过 MTU 计算的。

TCP 三次握手建设连贯

<img src="http://oss.mflyyou.cn/blog/20200802212532.png?author=zhangpanqin" alt="image-20200802212532628" style="zoom: 33%;" />

图片来自 码出高效:Java 开发手册

为什么是三次握手建设连贯呢?很多面试官也会问。这其实是牢靠连贯的起码握手次数。

<img src="http://oss.mflyyou.cn/blog/20200802212808.png?author=zhangpanqin" alt="image-20200802212808724" style="zoom:50%;" />

图片来自 码出高效:Java 开发手册

这里还有个 全连贯队列和半链接队列 的知识点

TCP 四次挥手断开连接

<img src="http://oss.mflyyou.cn/blog/20200802213247.png?author=zhangpanqin" alt="image-20200802213247725" style="zoom: 33%;" />

图片来自 码出高效:Java 开发手册

CLOSE_WAIT 是收到对方 FIN 包之后,回复 ACK 之后进入的状态。之后不会承受数据了,进行已收数据的业务解决之后,在发送一个 ACK+FIN,进入 LASK_ACK,而后期待对方发送 ACK,超时没有等到,会重试发送(内核能够配置重试发送次数)。当你发现服务端有大量的 CLOSE_WAIT 链接,服务端的代码有问题,须要排查。

TIME_WAIT 的链接多的话,服务端能够优化,不然这个链接会占用很长时间,在高并发的时候,会导致没有资源开释的慢。

MSL 为 Maximum Segment Lifetime,在 centos 中默认值为 60s

# sysctl -a | grep tcp_fin_timeout# 举荐小于 30,也不能太小,15-30net.ipv4.tcp_fin_timeout = 60

阐明 A 机器链接会在 120 s 之后能力开释。这个是为了保障 B 机器 能接管到最初一个 ACK,当处于 LAST_ACK 的超时没有收到A 发来的 ACK 的话,会重试发送一个 FIN+ACK。这个 2MSL 也是为了最大限度保障 B 机器失常敞开。

三次握手建设连贯四次挥手断开连接 须要联合抓包工具本人剖析一下,了解会更粗浅。

网络抓包

Wireshark 抓包剖析是很厉害的,mac oslinux 都有命令行程序 tshark,能够在服务器用 tshark 抓包,拿到本地来剖析。

抓包的时候肯定要指定抓什么包,什么包都抓的话,一会你的电脑内存就飙升好多(别问我为啥晓得,问就是 30g 内存都让它吃了)。

Wireshark 有个 抓包过滤器显示过滤器。抓包的时候指定抓什么包这是 抓包过滤器的作用,抓包之后显示显示那些内容那是 显示过滤器的作用

# -i 指定那个网卡 # -f 指定抓包过滤器# -Y 显示过滤器# -w 指定抓包数据到文件,没有 -w 输入屏幕# -V 显示 TCP/IP 每层包的详细信息,倡议将抓包的文件在图形化界面中查看,不指定 -Vtshark  -i en0 -f "tcp" -Y "http"# 抓取拜访 www.mflyyou.cn 的包tshark  -i en0 -w a.pcap -f "host www.mflyyou.cn"# 指定抓那个协定 tcp,ip,icmp,arp,udptshark  -i en0 -f "tcp"# host 指定域名或者 ip# port 指定端口# 拜访 www.mflyyou.cn 的包,或者 icmp. ping www.baidu.com 也会被抓到tshark  -i en0 -f "host www.mflyyou.cn || icmp"tshark  -i en0 -f "port 80"# 条件之间反对逻辑运算符 || && !# 抓取 ssh 链接的包tshark  -i en0 -f "host www.mflyyou.cn && port 22"

参考资料

《图解 TCP/IP》

linux-tcp 阐明

鸟哥私房菜:根底网络的概念


本文由 张攀钦的博客 http://www.mflyyou.cn/ 创作。 可自在转载、援用,但需署名作者且注明文章出处。

如转载至微信公众号,请在文末增加作者公众号二维码。微信公众号名称:Mflyyou