网络协议基本概念

204 阅读7分钟

7层模型和4层模型

什么是层,为什么要分层

一开始学习网络的时候就不理解别人说的7层4层模型。现在才知道,分层其实可以理解为代码里面的模块。我们当然可以把一个逻辑全部写在一个类里面,但是这样不容易维护,所以我们把代码按模块来划分。网络也是一样的,每个里面也都是代码,每层的代码实现自己的接口定义出来的东西,和java一样的。

7层模型

7层模型分的太过详细,有的人可能就觉得过度设计了,代码写的过于分散,所以把一些层的代码放到一起,产生了4层模型 image.png

4层模型

image.png 每层的协议不同 image.png

应用层

Http

Http协议是我们最了解的协议,每天都在用。属于应用层的协议,我们在程序中自定义他们的内容。没什么好说的,往下的协议就都是内核实现的程序,这才是我们需要关注其内部实现的东西。http怎么实现的是我们代码可以控制的。

传输控制层

TCP

聊到tcp协议就不得不提那个著名的 三次握手四次分手。tcp协议是可靠的,面向连接的协议。

public static void main(String[] args) throws Exception{
    Socket socket = new Socket();
    socket.connect(new InetSocketAddress("192.168.0.91",8080));
}

从这个最简单的demo可以看出,java属于应用层,当我们调用了 socket.connect方法的时候,并没有去手写 三次握手的代码,是内核帮我们实现的。

三次握手

当我们想和对方建立连接的时候,内核会先发送一个 SYN 包给对方,对方的内核收到后会回一个 SYN+ACK的包,我们收到这个包就表示我们发的数据对方可以收到,于是我们再发送一个ACK的包,然后我们本地就开辟一个socket连接。对方收到ACK的包之后表示对方发的SYN+ACK的包也能到达于是本地也开辟一个socket。这才是TCP认为可靠的含义,发送数据前需要确认双方都有能力收到数据。之后的每一次数据传输,对方都需要回一个ACK的包,表示上一个请求数据收到了。

四次挥手

当数据传输完毕,断开连接释放资源,需要经过四次挥手,一方首先发送 FIN包,对方收到后回一个ACK,然后自己也开始准备一些释放资源的前置操作,等自己也准备好释放资源了回再发送一个 FIN包,然后对方再回一个 ACK

为什么是4次分手,3次行不行

有的人可能会觉得为什么不能像3次握手那样收到FIN请求后直接回一个 FIN+ACK,然后对方再回一个ACK呢。其实是不行的。因为在服务端发送fin数据其实是调用了 socket.close方法,当服务端收到客户端想要断开连接的时候,需要有相应的逻辑,释放相关资源等。有可能这个时间超过了2MSL所以在收到FIN的时候需要马上回一个ACK。等自己这边准备好了,就调用 socket.close()方法,再发送一个FIN请求过去。

TCP的几个状态

说两个比较重要的,我工作中确实遇到的状态

image.png

CLOSE_WAIT & FIN_WAIT2

A发送FIN请求到B,B回复了一个ACK,之后,A的状态就变为 FIN_WAIT2意思是等待接下来的FIN请求。然后B的状态就变为 CLOSE_WAIT,意思是等待自己调用close方法,发送一个FIN包过去。如果B一直没有调用close方法,那么这个 CLOSE_WAIT将会永远存在 image.png 所以当发现服务器出现大量CLOSE_WAIT的时候,表示socket没有正常的关闭。

TIME_WAIT

当A收到B发送的FIN包后,回复了一个 ACK之后自己就会变成TIME_WAIT状态,因为并不确定这个ACK的包有没有到达B那边,所以需要等待 2MSL也就是两倍的网络传输最大时间,如果超过这个时间,对方还没发送消息就代表自己的ACK已经发送过去了。time_wait本身是正常的情况。但是默认情况下,time_wait还是占用端口号的。所以在这2MSL时间内,这个端口是不能再次被使用。在nginx这种转发的中间件机器上,高并发的情况下很容易把电脑自身的端口占用完导致没有端口使用,这时候就会爆出 address already in use:connect.解决办法: 编辑内核文件/etc/sysctl.conf,加入以下内容:/sbin/sysctl -p 生效

net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系默认的 TIMEOUT 时间

网络层

IP 协议

传输层解决的是如何让一个连接更稳定,通过三次握手和四次分手,加上ACK的机制保证消息的不丢失。但是TCP协议并没有找到对方机器的能力tcp协议仅仅只是保证消息的可靠而已

几个IP协议的概念

  1. IPADDR 也就是我们常说的IP地址,用于标识一台计算机在互联网中的位置
  2. NETMASK 掩码,把掩码跟IP地址按位与运算,就会获得这台计算机属于那个 网段
  3. GATEWAY 网关。 这个跟后面的路由表一起解释

路由表

[root@localhost ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.0.1     0.0.0.0         UG    100    0        0 enp5s0
192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 enp5s0

讲路由表之前得先说一下IP协议是如何存储别的机器的IP的。首先我们来看看两个网络之间的拓扑图

image.png 当192.168.1.123想跟192.168.2.123通信的时候,他其实并不知道2.123在网络的具体哪个位置。他只存储了周围一个节点距离的路由情况 也就是路由表。每个机器上都有一个路由表。

路由表的计算

现在知道了每个机器上并没有存储所有机器的ip地址,只有一个路由表就可以完成数据的发送,那么这个路由表到底是怎么运作的呢?当我们想请求某个ip的时候,会将ip地址和路由表的Genmask上的数据按位与运算,然后跟Destination对比,如果相同就把数据发送到对应的Gateway上

默认网关

知道了路由表的计算规则后,我们再来看路由表,我们发现了一个特殊的数据

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.0.1     0.0.0.0         UG    100    0        0 enp5s0

我们可以看到,不论什么ip地址与上0.0.0.0都会等于0.0.0.0,所以什么数据都会发送给192.168.0.1,这也就是默认网关。 知道了默认网关后这条又是什么意思呢?

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 enp5s0

gateway的含义是0.0.0.0要发送的数据直接就在这个机器的同一局域网内,不需要走网关。

链路层

arp协议(网络层和链路层很模糊,我觉得是链路层)

我们刚才知道了路由表之后,产生了一个问题,当我们发送数据的时候写的是目标的ip地址,经过路由表计算之后,得出了默认网关的地址,那么数据是如何发送到默认网关上的呢?这就牵扯出arp协议了

[root@localhost ~]# arp -a
? (192.168.0.93) at 70:9c:d1:f0:ed:71 [ether] on enp5s0
? (192.168.0.1) at 60:3a:7c:e0:d8:78 [ether] on enp5s0

ARP协议是ip地址和物理mac地址的映射。当网络层算出要把数据包发送给默认网关192.168.0.1之后,会通过arp协议找到默认网关的物理地址是 60:3a:7c:e0:d8:78.于是物理层就通过这个物理地址能找到物理网卡发送数据. 在网络传输过程中,arp协议里面封装的下一跳的物理地址是不断变化的

总结

一个请求差不可以看成是这么一个被包装的状态,每一层都拆自己对应的包然后解析判断,最外层的arp协议的 目标mac地址是不断变换的。 image.png