网络模型进阶

TCP

TCP的全称是Transmission Control Protocol,这个协议的目的就是创建一个Session,通过这个Session来传输数据。

什么是TCP?

面向连接的,可靠的传输协议。

我们在数据链路层是查看了源和目标的MAC地址,并且这个MAC地址,使我们能将数据从局域网中的一台设备发送到另一台设备,IP是从一个网络上的设备,与网络上的另一个设备进行通信,而TCP就是允许在网络上的两个设备之间,创建一个会话,通过这个会话,传输数据。

什么是面向连接?三次握手

三次握手和四次分手

三次握手:

  1. 首先由客户端发起SYN信号:我准备要发数据了
  2. 由服务端携带SYN返回ACK:你要发数据这个请求我收到了
  3. 再由客户端返回ACK通知服务端:好的,那我开始发数据了

一旦完成了三次握手,双方系统内核会开辟资源(线程、缓冲区等),这个资源是为对方未来发送数据包接收和传递到下一层服务用的。只有双方都开辟了资源,连接才算建立成功。

为什么是三次握手而不是两次握手?

  1. 如果是两次握手,客户端第一次发送请求进入信道,但是在某个节点滞留了,服务端没有第一时间接收到这个请求,客户端在一段时间没有收到服务端的响应而再次发送想要确认连接的信号,这个时候服务端收到请求后进入连接状态,双方开始发送数据,关闭连接之后第一次连接请求被服务端获取,开辟资源等待客户端发送数据,而客户端根本不知道自己要发送数据,这样服务端就会白白的浪费了资源。
  2. 如果是两次握手,不能保证在不稳定的信道里进行稳定的数据传输,服务器只确定了客户端到服务器的连接,而不能确定自己到客户端的连接。
  3. 如果是两次握手,就像DOS,DDOS攻击,没有返回的ACK,我就开辟了大量的资源。而三次握手,我没有接收到你的ACK,我就不会开辟资源,不会造成资源浪费。

image-20220306162430981

服务端:

  • syn_listen:服务端进行监听

  • syn_rcvd:服务端收到连接请求后等待客户端响应

    如果长时间大量处于这个状态没有收到客户端的响应,可能有两种情况:

    • 请求方没有收到服务器发送的SYN+ACK,这种情况只要能PING通对方主机就可以排除
    • 对方收到了却没有发送ACK,这里也分为两种情况:
      • 对方不打算返回ACK,如DOS/DDOS攻击
      • 对方收到的SYN+ACK不合法

    服务器端的连接一直保持在SYN_RCVD状态(半开连接)直到超时。

客户端:

  • syn_send:等待对方返回SYN+ACK

四次分手:

  1. 服务端先给客户端FIN1信号:响应完客户端迫不及待想断开连接,首先发送FIN说我没有数据要发送了
  2. 客户端携带FIN1返回ACK1:好的我知道了
  3. 客户端再给服务端FIN2信号:我也没有数据要发送了
  4. 服务端带着FIN2返回ACK2:好的我知道了

image-20220306162421356

先断开连接的一端,可能是客户端,可能是服务端

FIN_WAIT_1:等待FIN1+ACK

FIN_WAIT_2:等待FIN2

TIME_WAIT:等待超时

如果服务端出现大量的TIME_WAIT是什么情况:

  1. 在高并发场景中,大量的短链接存在,TIME_WAIT连接存在属于正常现象
  2. HTTP 请求中,如果 connection 头部取值被设置为 close 时,基本都由「服务端」发起主动关闭连接
  3. TCP 四次挥手关闭连接机制中,为了保证 ACK 重发和丢弃延迟数据,设置 time_wait 为 2 倍的 MSL(报文最大存活时间2min)4min

解决上述 time_wait 状态大量存在,导致新连接创建失败的问题,一般解决办法:

  1. 客户端,HTTP 请求的头部,connection 设置为 keep-alive,保持存活一段时间:现在的浏览器,一般都这么进行了

  2. 服务器端

    允许 time_wait 状态的 socket 被重用

    缩减 time_wait 时间,设置为 1 MSL(即,2 mins)

如果客户端出现大量的CLOSE_WAIT状态是什么情况:

  1. 服务端程序没有正常关闭socket
  2. 服务端的CPU太忙了,处理不过来
  3. 应用程序一直阻塞在其他地方,可能是锁,IO等

为什么要4次分手而不是3次或两次?

  1. 我做了一个模拟的服务端接收文件传输,客户端通过NIO的零拷贝发送数据,客户端很快就进行了close操作,通过抓包看到服务器还在接收包,如果两次分手的话,这个时候客户端已经断开连接,如果有失败的、错误的包,我需要你重新给我发一次这个数据包已经是不可能的了。只有所有数据已经接收完,才能向客户端发出断开连接的请求。
  2. 客户端先断开连接
  3. 服务端先断开连接

为什么要在time_wait等待2MSL才能closed

如果不等待2MSL,我发出了ack包对方没收到,还会进行确认,这个时候我资源已经断开,不能返回ack,对方将一直处于LAST_ACK状态,而不能释放资源,2MSL也是为了确保网络中已经没有了我们之间的资源包,所有数据在网络中已经清掉了,不怕对方没有接受完。

抓包命令:

tcpdump -nn -i eth0 port 9090

端口号

端口号的范围是0-65535,通过端口号分为三个不同的类型

  • 公认端口0 - 1023
  • 注册端口 1024-49151
  • 临时端口 49152-65535

客户端一般用临时端口号,主要是为了会话的临时时间段。

image-20220306223301536

每一个协议都需要头

segment

image-20220307015711541

packet

源端口,目标端口,标识符,请求序号,序列号,确认号,负载

image-20220307020008116

源IP,目标IP,长度,其他信息,源端口,目标端口,标识符,序列号,确认号,负载

image-20220307020438696

TCP拥塞模型

TCP是可靠的,可以把数据从一个端点传到另一个端点,但是它不希望两者之间的网路不堪重负,TCP不想非常快的就开始发送数据,这样会导致拥塞和数据包丢失,同样TCP也不想占用其他的网络,把其他所有协议都淘汰掉,优先考虑自己的流量,因此通过TCP拥塞控制,TCP能够确定网络上的拥塞,相应的调整其传输的速率。

窗口大小限制:

  • 慢启动
  • 快速启动

拥塞检测机制

  • 丢包
  • 测量延时

UDP

image-20220307142250538

IP

什么是IP地址

  • IP地址由用.分割的四组数字组成
  • IP地址被分配给网络上设备的网卡,并且我们的IP地址被分为两部分。它具有网络部分和主机部分
    • 网络部分:标识联网设备(邮编)
    • 主机部分:标识特定网络上的单个设备(门牌号)

IP地址的格式

IP地址以四个十进制数字的格式写入

比如:192.168.0.1,每一个段有8位字节,最大到255

地址类型

网络地址:是指系统中一组设备,或者一组IP地址的标识符(邮政编码),代表IP地址范围,简称为网络前缀/前缀

广播地址:是网络上所有设备的一个标识符

主机地址:是确认在网络中的独一的设备,比如一台电脑,一台打印机,如果要为一台计算机想要一个IP地址,那么该计算机必须具有主机的地址,并且不能为其分配网络地址或广播地址

例:

image-20220306020718642

子网掩码是个不变值,所以主机地址的范围就是1~254。

私有地址和公有地址

私有地址只允许在一个小范围内部使用

10.0.0.0 — 10.255.255.255

172.16.0.0 — 172.31.255.255

192.168.0.0 — 192.168.255.255

看透IP

IP头:

image-20220306020659404

Version:IPV4,这个版本号就是4,4bit

Internet Header Length:网络头部长度,4bit

Type of Service:8bit

Total Length:总长度包括头和数据 16bit

每行32bit。

Protocol:指定下一层协议(TCP/UDP)

通过抓包可以看到上面信息:

image-20220306024943477

IP地址的分类和组成

分类网络

image-20220306025432113

A类:前8位网络部分,后面24位是主机部分

B类:前16位网络部分,后15位是主机部分

C类:前24位网络部分,后8位是主机部分

D类:前32位全是网络部分,主要用于广播

E类:用于实验

很浪费IP,所以后来有了子网掩码。

无类寻址

通过在子网掩码中放置一个我们想要的网络部分,并在想要宿主部分的位置用零来告诉我们地址网络的哪个部分是主机。1995年添加到IP地址上的一种技术。通过1来确定是网络部分,通过0来确定是主机部分

例:

255.255.255.0,那么我们想要的就是前24位是网络部分,后8位是主机部分

255.255.0.0,那么我们想要的就是前16位是网络部分,后16位是主机部分

通过子网掩码,我们就不再需要分类,不用浪费那么多IP。

IP路由

子网的框架

简单案例:

IP:203.0.113.10

子网掩码:255.255.255.0

前多少位是网络地址? 24位

子网框架:203.0.113.10/24 无类域间路由(CIDR)

复杂案例:

有八个工作地点,北京上海内蒙云南等

分配了 203.0.113.0/24 给你,而我需要八个网络段,怎么分8个网络地址?

  1. 可分配地址在203.0.113.0 ~ 203.0.113.255

  2. 二进制表示:

    11001011.00000000.01110001.00000000~11001011.00000000.01110001.11111111

  3. 2^3 = 8,所以需要分配3个bit进行分配11001011.00000000.01110001.xxxxxxxx

  4. 11001011.00000000.01110001.000XXXXX-北京 203.0.113.0/27 203.0.113.0-203.0.113.31
    11001011.00000000.01110001.001XXXXX-天津 203.0.113.32/27 203.0.113.32-203.0.113.63
    11001011.00000000.01110001.010XXXXX-上海 203.0.113.64/27 203.0.113.64-203.0.113.95
    11001011.00000000.01110001.011XXXXX-内蒙 203.0.113.96/27 203.0.113.96-203.0.113.127
    11001011.00000000.01110001.100XXXXX-湖北 203.0.113.128/27 203.0.113.128-203.0.113.159
    11001011.00000000.01110001.101XXXXX-重庆 203.0.113.160/27 203.0.113.160-203.0.113.191
    11001011.00000000.01110001.110XXXXX-云南 203.0.113.192/27 203.0.113.192-203.0.113.223
    11001011.00000000.01110001.111XXXXX-江苏 203.0.113.224/27 203.0.113.224-203.0.113.255

    不同IP之间通过路由器连接。

    例:

    我在阿里云的IP是 123.56.85.103 01111011.00111000.01010101.01100111

    子网掩码255.255.240.0/20 11111111.11111111.11110000.00000000

    我被分配的地址区间123.56.80.0 ~ 123.56.240.255 之间

    image-20220307001117028

    image-20220307001644338

    我所在的局域网:169.254.0.0/172.21.96.0两个,我在局域网内通讯不需要其他路由器,都表示为0.0.0.0

    ping百度110.242.68.4与0.0.0.0做与运算得到110.242.68.4,与Destination中的0.0.0.0一样,路由表下一跳的路由就是 172.21.111.253 这个地址;

    如果是访问局域网172.21.96.0 ~ 172.21.111.255,与掩码255.255.240.0做与运算得到172.21.96.0,那么下一跳不需要走网关。

    如果是访问局域网169.254.0.0 ~ 169.254.255.255,与掩码255.255.0.0做与运算得到169.254.0.0,一样 不需要下一跳走网关即可访问。

    另因我子网掩码是11111111.11111111.11110000.00000000,所以我局域网中的广播地址为172.21.111.255,我在公网的广播地址应该是123.56.95.255,即01111011.00111000.01011111.11111111

现在知道什么是路由表,什么是下一跳,什么是网关了

MAC

image-20220307013338706

image-20220307013453053

路由器网卡的硬件地址,所以最终数据包外层套了下一跳的硬件地址,内层套了一个百度的IP地址,外层的硬件地址决定先把这个数据交给路由器,再由路由器维护的路由表决策他的下一跳。这个时候换成再下一条的硬件MAC地址。arp协议就是获取网卡物理地址的一种协议。

总结

  1. 网络中,客户端与服务端建立连接整个过程:

    • 首先要知道是从应用层到传输层到网络层再到链路层逐层调用,数据链路层开机时还没来得及维护ARP协议获取到MAC地址,就会产生阻塞,等待ARP协议调用,获取MAC地址后回调所有调用,再从应用层开始调起

    • image-20220307150206458

    • 拿到下一跳的MAC地址,IP一直都是绑定的百度的IP,百度IP通过路由表按位与的算法找到网关下一跳的IP,并将数据包发送到该IP的MAC地址,将数据包交给下一跳,直到找到百度的IP和百度的MAC地址。这其中只有MAC在变,所以叫链路

      image-20220307150856524

      最终通过TCP的端口号找到百度服务器上对应的进程

也可以解释了链路层是节点与节点连接,网络层是点到点的关系(IP到下一跳IP),最终传输层才是端到端的关系。

  1. 另外扩展一下我们打游戏的时候,明明下载网速很快,为什么会丢包,导致人物在地图上乱跑?

    • 首先下载我们采用的TCP,经过TCP拥塞能确保在网络中的传输窗口大小是一直在变动的,如果网络不稳定,会控制你这个时候窗口变小,传输的慢一点,等到网络恢复通过快速启动机制保证能恢复带宽能接受的窗口大小。

    • 而打游戏为了响应速度启用的是UDP,也就是不稳定的连接,无论你网络中是否发生波动,我都按着最开始确定的大小给你发送,如果网络波动,影响你接收的先后顺序或者未接收到,都会继续发送,最后可能导致断触或者画面“丢包”。

posted @   coderElian  阅读(31)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示