你须要知道的TCP/IP

前言

TCP/IP 协议 是网络通讯的基石,TCP/IP 协议 不是只有 TCPIP 协议,它是整个网络通讯中全部协议的简称。php

维基百科:TCP/IP协议簇)html

维基百科:OSI模型java

# 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%;" />linux

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

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

应用层:应用程序通讯细节的协议,好比经常使用的 HTTPredis

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

网络层:地址管理和路由选择,在两点之间找到一条最佳的通讯路线,通讯标识是 IP后端

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

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

网络通讯能够作什么呢?

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 地址的做用后文中会介绍。

image-20200801144243065

交互机和路由器的区别

<font color=red>这部份内容是我本身的理解,我没有在网上找到资料佐证,请谨慎对待</font>

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

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

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

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

TCP/IP 通讯

TCP_IP 同一以太网 (2)

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

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

数据链路层

image-20200801220255714

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

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

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

# 查看网卡对应的 MTU
ifconfig -a
netstat -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%;" />

# 解析域名的 ip
dig 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 地址。

image-20200801223925086

通讯过程分析

未命名文件

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

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

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

# 查看路由表
route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.31.1    0.0.0.0         UG    100    0        0 eth0

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

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

五、到下一个路由器节点,路由器解包,看是发给本身的数据包(根据帧中的目的 MAC 地址与本身的 MAC 地址比较),不是就丢弃了;是的话就会解包拿到 目的 IP (47.104.168.20),而后在当前路由器上根据路由表查询下一跳,发送给下一个节点;。。。。 直到目的服务器,或者发送的包 TTL 为 0

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

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

image-20200801230015436

<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 告诉 发送端 调整窗口大小。

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

未命名文件 (2)

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

滑动窗口百度百科)

校验和 (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,这个值须要根据首部计算

image-20200802211639395

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-30
net.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 每层包的详细信息,建议将抓包的文件在图形化界面中查看,不指定 -V
tshark  -i en0 -f "tcp" -Y "http"

# 抓取访问 www.mflyyou.cn 的包
tshark  -i en0 -w a.pcap -f "host www.mflyyou.cn"

# 指定抓那个协议 tcp,ip,icmp,arp,udp
tshark  -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

相关文章
相关标签/搜索