Linux高级--2.4.1 网络概念(分层、TCP)

news2024/12/27 3:52:39

关于网络分层理解的难点 

        对于一般人(不参与设计和维护网络协议栈的人)来讲,物理层和应用层很容易理解,也很好记住。首先,物理层是看的到的网线、基站的实体。再者,应用层是用户自己参与编写的程序。

而那些不长接触的数据链路层、IP层、网络层 确实最难理解和记住的。下面的内容会重点讲这三层。

        应该很多人有这样的疑问:IP层和网络层为什么不合并在一起,既然分层那这两层的界限在哪?数据链路层又和IP层之间的界限又在哪?

        IP层和网络层为什么不合并在一起?

                1. 有些协议只工作在IP层,比如IPv4/IPv6、ICMP、ARP、RIP、OSPF、BGP、

                    IGMP等。(这些协议操作是针对IP的存在相关的)

                2. IP层对于包的传输有自己的策略:上层给的长度大于MTU,则分片,收到分片的包要

                    合并,一个片丢了则所有片都丢掉。校验不过则丢掉,没有重传、备份、确认机制。

                    这样尽可能保证IP层任务处理的简单性,最小化性---这也是保证运行在IP层协议的

                    轻量性。至于数据完整性,则靠上层协议自己保证--》使得上层协议的的多样性。

                    因为上层协议就是可能必须要可靠传输(TCP),或者必须要不可靠传输(UDP)。

        IP层和MAC层为什么不合并?

                1. 有的协议只在MAC层工作:主要涉及物理地址和链路层的控制,如Ethernet、gPTP、

                    HDLC、PPP、Wi-Fi、VLAN、Frame Relay、FDDI等。(这些协议是针对设备的操

                    作,因为一个设备通常是一个网卡)

                2. MAC层没有分包和组包,因为网卡为了保证传输的速度只管收包,且MAC一般依赖网

                     卡的DMA技术快速缓存移动(不依赖CPU),没法分包和组包。所以分包和组包的

                     工作就交给上层了。

                3. MAC层有重传,对设备来说是守大门的,对于最基本的CRC校验错误的包,不能让流

                    转回上层,否则就浪费了资源和时间。

        

// 一个IPv4数据包的结构
struct ip_packet {
    uint8_t version;      // IP版本(IPv4或IPv6)
    uint8_t ihl;          // IP头部长度
    uint8_t tos;          // 服务类型
    uint16_t total_len;   // 总长度(IP头部 + 数据部分)
    uint16_t id;          // 标识
    uint16_t frag_off;    // 分片偏移
    uint8_t ttl;          // 生存时间
    uint8_t protocol;     // 协议类型(TCP或UDP等)
    uint16_t checksum;    // 校验和
    uint32_t src_ip;      // 源IP地址
    uint32_t dest_ip;     // 目的IP地址
    uint8_t *data;        // 数据部分(载荷),指向TCP或UDP段
};

struct tcp_segment {
    uint16_t src_port;       // 源端口
    uint16_t dest_port;      // 目的端口
    uint32_t seq_num;        // 序列号
    uint32_t ack_num;        // 确认号
    uint8_t data_offset;     // 数据偏移(TCP头部长度)
    uint8_t flags;           // 控制标志位(如SYN, ACK, FIN等)
    uint16_t window_size;    // 窗口大小
    uint16_t checksum;       // 校验和
    uint16_t urgent_pointer; // 紧急指针
    uint8_t *data;           // 数据部分(载荷)
};

struct udp_datagram {
    uint16_t src_port;       // 源端口
    uint16_t dest_port;      // 目的端口
    uint16_t length;         // UDP长度(头部 + 数据)
    uint16_t checksum;       // 校验和
    uint8_t *data;           // 数据部分(载荷)
};

struct sock {
    struct socket *socket;             // 套接字的实际结构
    struct net_device *dev;            // 绑定的网络设备
    struct sockaddr_in local_addr;     // 本地地址和端口
    struct sockaddr_in remote_addr;    // 远程地址和端口
    unsigned short state;              // 套接字的状态
    unsigned int flags;                // 套接字的标志
    struct sk_buff_head sk_receive_queue; // 用于接收数据的队列
    struct sk_buff_head sk_send_queue;    // 用于发送数据的队列
    int protocol;                      // 协议类型(UDP,TCP等)
    ...
};


struct tcb {
    unsigned long seq;            // 当前的发送序列号
    unsigned long ack;            // 当前的接收确认号
    unsigned long snd_wnd;        // 发送窗口大小
    unsigned long rcv_wnd;        // 接收窗口大小
    unsigned long snd_nxt;        // 下一次要发送的序列号
    unsigned long rcv_nxt;        // 下一次要接收的序列号
    unsigned long rcv_buf_size;   // 接收缓冲区大小
    struct sockaddr_in src_addr;  // 源地址
    struct sockaddr_in dest_addr; // 目标地址
    int state;                    // 连接的当前状态(例如 ESTABLISHED, SYN_SENT 等)
    // 其他字段,包括缓冲区、计时器、重传机制等
};


struct sk_buff {
    struct sk_buff *next;       // 链表中的下一个skb,用于链表或队列中的组织
    struct sk_buff *prev;       // 链表中的前一个skb
    struct net_device *dev;     // 指向网络设备的指针(网络接口卡)
    unsigned int len;           // 数据包长度
    unsigned char *data;        // 数据指针,指向包的有效载荷
    unsigned char *tail;        // 数据包尾指针
    unsigned char *end;         // 数据包的结束指针
    unsigned char *head;        // 数据包的起始指针
    struct socket *sk;          // 套接字,指向相关的socket
    unsigned int protocol;      // 协议字段,标识当前skb的数据类型(比如IP,ARP等)
    unsigned int priority;      // 包的优先级
    struct dst_entry *dst;      // 路由目的地信息(用于IP层)
    struct sk_buff *next_free;  // 空闲链表中的下一个skb
    ...
};

网络层与传输层概述

网络层:
  • 抽象概念:网络层是基于 IP 的抽象概念,与数据链路层用 MAC 地址标记设备不同。MAC 地址是一种具体化的概念,绑定于所在的物理网络,而 IP 地址可以是固定的,也可以通过路由动态变化。
  • 功能:所有“网络”的“网”是基于 IP 的抽象概念,而链路层的“路”是基于 MAC 的具体化概念。
传输层:
  • 协议决定内容:传输层与物理信号的形式(光信号、电信号、无线信号)或目的地无关,传输层的协议决定了传输的内容是可靠的还是不可靠的。例如:
    • 不可靠传输协议:适用于允许丢帧和数据丢失的流媒体传输。
    • 可靠传输协议:适用于需要保密、稳定且不允许数据损坏或丢失的场景,并能控制传输的速度和质量。

数据链路层的作用与网卡驱动

数据链路层的命名

数据链路层之所以称为“链路层”,是因为它负责在物理链路上传输数据。链路指网络中相邻节点之间的物理连接(例如两台计算机或交换机)。

数据链路层的主要作用
  1. 帧的封装和拆解

    • 把网络层的数据打包成帧(Frame)。
    • 在接收端解包帧,提取网络层数据。
  2. 差错检测与纠正

    • 使用校验和机制(如 CRC)检测传输过程中的错误。
    • 部分情况下还能纠正错误。
  3. 流量控制与重传

    • 控制数据流速,防止发送过快导致接收端无法处理。
    • 在数据帧丢失时请求重传。
  4. MAC 地址管理

    • 确保数据在局域网内正确发送到目标设备。
数据链路层与网卡驱动的关系
  • 数据链路层的职责:定义如何在物理链路上传输帧,并确保数据传输的可靠性。
  • 网卡驱动的职责
    • 是数据链路层的一部分。
    • 负责从网卡接收数据并传递给网络层。
    • 与操作系统协作完成数据链路层功能。
数据链路层与网络层的关系
  1. 网络层的职责:负责逻辑寻址和跨网络的数据路由。
  2. 网络层的工作方式
    • 接收来自链路层的帧,解封装出 IP 数据包。
    • 基于 IP 地址和路由信息,将数据传递到目的地。

TCP/IP 协议栈

 tcp组包时 校验和 计算 -- 按照协议中指出,校验和本身在校验时 作为0计算。

校验和前面 还包含了 伪包头 包含了IP地址,是为了防止路由错IP 

主要组成部分
  1. 链路层(Link Layer):对应 OSI 模型中的数据链路层。
  2. 网络层(Internet Layer):主要协议是 IP,负责跨网络的数据路由。
  3. 传输层(Transport Layer):如 TCP 和 UDP,提供端到端的数据传输。
  4. 应用层(Application Layer):处理应用数据和服务,如 HTTP、FTP。
数据包的传递流程
  • 链路层负责在物理网络中传输数据帧。
  • 网络层通过路由实现数据的跨网络传递。
  • 传输层提供可靠或不可靠的数据传输服务。

网卡驱动与 sk_buff 结构体

sk_buff 的作用
  • 是 Linux 内核中描述网络数据包的重要数据结构。
  • 用于存储和管理网络协议栈的所有数据包。
典型的数据包接收流程
  1. 网卡驱动接收数据
    • 网卡驱动接收到数据包后,分配一个 sk_buff
    • 将数据存储到 sk_buff 的缓冲区中。
  2. 传递给协议栈
    • 通过 netif_rx() 等函数将 sk_buff 传递给网络层。
  3. 网络层处理
    • 解封装数据,提取 IP 包进行进一步处理。
sk_buff 的主要字段
  • data:指向数据部分。
  • len:数据长度。
  • protocol:上层协议类型。
  • dev:关联的网络设备。
  • 头部信息指针:mac_headernetwork_headertransport_header
sk_buff 示例
struct sk_buff *skb = netdev_alloc_skb(dev, len);
if (!skb) {
    return -ENOMEM;
}
memcpy(skb_put(skb, len), data, len);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);

传输层与 TCB 结构体

TCB 的作用
  • 传输控制块(TCB, Transmission Control Block)用于管理和维护 TCP 连接。
  • 在Linux内核中,TCB(Transmission Control Block)是专门为TCP通信服务的,它是TCP连接的核心数据结构,用来维护和管理每个TCP连接的状态。在UDP中并没有类似于TCP的TCB结构,因为UDP是无连接的协议,它不需要维护像TCP那样的复杂状态。

    对于TCP,TCB通常是指Linux内核中的struct tcp_sock,它继承自struct inet_sock,而后者又继承自struct sock。这些结构体联合起来负责维护一个TCP连接的各种状态和信息。

    ,TCB 主要由 struct tcp_sock 表示。
tcp_sock 定义位置
  • 定义于 include/net/tcp.h
TCB(struct tcp_sock)的主要成员变量:
  1. 发送和接收窗口

    • snd_wnd:发送窗口的大小。
    • rcv_wnd:接收窗口的大小。
    • snd_nxt:下一个要发送的字节序列号。
    • rcv_nxt:下一个期望接收的字节序列号。
  2. 重传和拥塞控制

    • snd_cwnd:拥塞窗口,用于拥塞控制。
    • snd_ssthresh:慢启动阈值,用于拥塞控制。
    • retransmit_timer:重传定时器,用于控制何时触发重传。
  3. 连接状态和控制

    • state:TCP连接的状态(例如,ESTABLISHEDSYN_SENTCLOSED等)。
    • fastopen_req:快速打开请求的相关信息。
  4. RTT(往返时间)和RTO(重传超时)

    • srtt_us:平滑的往返时间,用来估算RTO。
    • rttvar_us:RTT变化,用于计算RTO。
    • rto:重传超时的值。
  5. 序列号和确认号

    • snd_una:已发送但未确认的最早字节序列号。
    • snd_up:紧急指针的序列号。
    • rcv_up:接收端的紧急指针。
  6. TCP选项

    • tcp_header_len:TCP头的长度。
    • tcp_mstamp:TCP报文的时间戳。
    • options:TCP连接的选项,例如SACK(选择性确认)、TS(时间戳)等。
  7. 定时器

    • delack_timer:用于延迟确认ACK的定时器。
    • retransmit_timer:重传定时器。
tcp_sock 的连接生命周期
  1. 初始化:三次握手时分配并初始化。
  2. 状态更新:更新发送和接收窗口的序列号。
  3. 关闭连接:释放 tcp_sock,完成连接关闭。
传输层的数据流向
  • 发送方向
    • 数据通过 send() 进入传输层,存储到发送缓冲区。
    • 在合适时机发送到网络。
  • 接收方向
    • 数据通过网卡驱动传递到 sk_buff,存储到接收缓冲区。
    • 应用层通过 recv() 获取数据。
tcp_sock 示例
struct tcp_sock {
    __u32 snd_nxt;
    __u32 rcv_nxt;
    __u32 snd_una;
    struct sk_buff_head write_queue;
    struct sk_buff_head receive_queue;
    // 其他状态变量
};
TCB的连接状态和半连接状态:

是的,在TCP协议中,TCB(Transmission Control Block)不仅维护与连接状态相关的信息,还负责管理全连接队列半连接队列,这些队列在TCP三次握手过程中起着非常重要的作用。

在Linux内核中,全连接队列半连接队列分别管理已经建立和正在建立的TCP连接。这些队列的核心与struct sock以及相关的数据结构密切相关。

  1. 半连接队列(Syn Queue)
    • 半连接队列中保存的是处于SYN_RECEIVED状态的连接,即那些客户端发起了SYN请求,服务端回复了SYN+ACK,但还未收到客户端的ACK确认的连接。
    • 这些连接还没有完全建立,仍在等待客户端的最终ACK。
    • 半连接队列是为了解决TCP三次握手中的中间状态,常用于抗击SYN Flood攻击(半连接攻击)等问题。

    在Linux内核中,半连接队列由struct request_sock管理,它是inet_csk模块的一部分。半连接队列使用inet_csk_reqsk_queue来处理。

  2. 全连接队列(Accept Queue)
    • 全连接队列中保存的是已经完成三次握手、处于ESTABLISHED状态的连接,即已经完全建立的TCP连接。
    • 服务端已经准备好接受数据传输,等待应用程序调用accept()函数来从队列中取出连接。
    • 全连接队列的大小可以通过/proc/sys/net/ipv4/tcp_max_syn_backlog参数进行调整,它定义了全连接队列的最大长度。

    在Linux内核中,已建立的连接由struct sock(具体来说是struct tcp_sock)管理,已完成的连接进入全连接队列等待应用层程序的处理。

相关结构体
  • 半连接队列(struct request_sock:用于管理尚未完全建立的连接。
  • 全连接队列(struct tcp_sock:用于管理已经建立的TCP连接。
三次握手过程中的队列变化
  1. 客户端发送SYN

    • 服务端收到客户端的SYN请求后,在半连接队列中创建一个新的request_sock条目,并进入SYN_RECEIVED状态。
  2. 服务端发送SYN+ACK

    • 该连接在半连接队列中继续等待客户端的ACK确认。
  3. 客户端发送ACK

    • 一旦服务端收到客户端的ACK,三次握手完成,服务端会将该连接从半连接队列中移出,放入全连接队列中。
    • 之后,服务端等待应用程序通过accept()函数来处理这个连接。
总结
  • 半连接队列:用于存放正在进行TCP三次握手、未完全建立的连接,服务端处于SYN_RECEIVED状态。
  • 全连接队列:存放已完成三次握手、处于ESTABLISHED状态的连接,等待应用层处理。

这两个队列在TCP连接建立过程中起到了维护连接状态、管理连接流量的作用。


0voice · GitHub


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2266152.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用VSCode Debugger 调试 React项目

一般我们调试代码时,用的最多的应该就是console.log方式了,还有的是使用Chrome DevTools 通过在对应的 sourcemap代码位置打断点进行调试,除了上面两种方式外还有一种更好用的调试方式: VSCode Debugger。 VSCode Debugger可以直…

Redis-十大数据类型

Reids数据类型指的是value的类型,key都是字符串 redis-server:启动redis服务 redis-cli:进入redis交互式终端 常用的key的操作 redis的命令和参数不区分大小写 ,key和value区分 查看当前库所有的key keys * 判断某个key是否存在 exists key 查看key是什…

Git--tag标签远程管理

目录 一、git 标签 tag管理 1.创建一个轻量级标签 2.创建一个带有附注的标签 3.删除标签 二、标签推送 1.再创建两个分支 2.把多个标签推送到远程 三、标签拉取 四、删除远程标签 1.命令 2.查看远程仓库,标签被删除 3.远程标签删除后本地标签不会消失&a…

通过nginx设置一个图片服务器,并使用 Nginx 作为反向代理

通过nginx设置一个图片服务器,并使用 Nginx 作为反向代理 安装nginx 首先需要去官网下载一个nginx,我这里下载了最新的稳定版本:nginx-1.26.2,下载下来是一个压缩包,解压之后就可以直接用了。 修改nginx的配置文件 …

第十六届“蓝桥杯”全国软件和信息技术专业人才大赛简介及资料大全

蓝桥杯全国软件和信息技术专业人才大赛是由工业和信息化部人才交流中心主办的一项全国性竞赛,面向全国高校大学生,累计参赛院校超过1200余所,参赛人数达40万人,是我国极有影响力的高校IT类赛事。 “第十六届蓝桥杯全国软件和信息…

快速理解24种设计模式

简单工厂模式 建立产品接口类,规定好要实现方法。 建立工厂类,根据传入的参数,实例化所需的类,实例化的类必须实现指定的产品类接口 创建型 单例模式Singleton 保证一个类只有一个实例,并提供一个访问他它的全局…

【山西长治】《长治市市直部门政务信息化建设项目预算编制规范和预算编制标准》(长财行[2022]25号)-省市费用标准解读系列32

《长治市市直部门政务信息化建设项目预算编制规范和预算编制标准(试行)》(长财行[2022]25号)于2022年8月1日开始试行,此标准由长治市财政局、长治市行政审批管理局编制,是对信息化建设项目预算管理的基本要求,主要适用…

Docker 入门:如何使用 Docker 容器化 AI 项目(二)

四、将 AI 项目容器化:示例实践 - 完整的图像分类与 API 服务 让我们通过一个更完整的 AI 项目示例,展示如何将 AI 项目容器化。我们以一个基于 TensorFlow 的图像分类模型为例,演示如何将训练、推理、以及 API 服务过程容器化。 4.1 创建 …

Java和Go语言的优劣势对比

文章目录 Java和Go语言的优劣势对比一、引言二、设计哲学与语法特性1、设计哲学2、语法特性 三、性能与内存管理1、性能2、内存管理和垃圾回收 四、并发编程模型五、使用示例1、Go语言示例代码2、Java语言示例代码 六、对比表格七、总结 Java和Go语言的优劣势对比 一、引言 在…

Docker怎么关闭容器开机自启,批量好几个容器一起操作?

环境: WSL2 docker v25 问题描述: Docker怎么关闭容器开机自启,批量好几个容器一起操作? 解决方案: 在 Docker 中,您可以使用多种方法来关闭容器并配置它们是否在系统启动时自动启动。以下是具体步骤和…

Pytorch | 利用BIM/I-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击

Pytorch | 利用BIM/I-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集BIM介绍基本原理算法流程 BIM代码实现BIM算法实现攻击效果 代码汇总bim.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器: Pytorch | 从零构建AlexNet对CIFAR10进行分类 Py…

网狐旗舰版源码搭建概览

简单的列一下: 服务端源码内核源码移动端源码核心移动端源码AI控制工具源码多款子游戏源码前端、管理后台、代理网站源码数据库自建脚本UI工程源码配置工具及二次开发帮助文档 编译环境要求 VS2015 和 Cocos3.10 环境,支持移动端 Android 一键编译&am…

【QT】:QT(介绍、下载安装、认识 QT Creator)

背景 🚀 在我们的互联网中的核心岗位主要有以下几种 开发(程序员)测试运维(管理机器)产品经理(非技术岗位,提出需求) 而我们这里主要关注的是开发方向,开发岗位又分很…

MySQL 数据”丢失”事件之 binlog 解析应用

事件背景 客户反馈在晚间数据跑批后,查询相关表的数据时,发现该表的部分数据在数据库中不存在 从应用跑批的日志来看,跑批未报错,且可查到日志中明确显示当时那批数据已插入到数据库中 需要帮忙分析这批数据丢失的原因。 备注:考虑信息敏感性,以下分析场景测试环境模拟,相关数据…

熊军出席ACDU·中国行南京站,详解SQL管理之道

12月21日,2024 ACDU中国行在南京圆满收官,本次活动分为三个篇章——回顾历史、立足当下、展望未来,为线上线下与会观众呈现了一场跨越时空的技术盛宴,吸引了众多业内人士的关注。云和恩墨副总经理熊军出席此次活动并发表了主题演讲…

Spring01 - 工厂篇

Spring入门(上)-工厂篇 文章目录 Spring入门(上)-工厂篇一:引言1:EJB存在的问题2:什么是Spring3:设计模式和反射工厂 二:第一个spring程序1:环境搭建2:核心API - ApplicationContext2.1&#xf…

攻防世界 unserialize3

开启场景 题目为unserialize3,这个单词在php中代表反序列化,代码 __wakeup 也是php反序列化中常见的魔术方法,所以这个题基本就是和反序列化有关的题目。根据代码提示,编写一个Exploit运行,将对象xctf的信息序列化 得到…

汽车免拆诊断案例 | 2011 款奔驰 S400L HYBRID 车发动机故障灯异常点亮

故障现象 一辆2011款奔驰 S400L HYBRID 车,搭载272 974发动机和126 V高压电网系统,累计行驶里程约为29万km。车主反映,行驶中发动机故障灯异常点亮。 故障诊断 接车后试车,组合仪表上的发动机故障灯长亮;用故障检测…

GitLab安装及使用

目录 一、安装 1.创建一个目录用来放rpm包 2.检查防火墙状态 3.安装下载好的rpm包 4.修改配置文件 5.重新加载配置 6.查看版本 7.查看服务器状态 8.重启服务器 9.输网址 二、GitLab的使用 1.创建空白项目 2.配置ssh 首先生成公钥: 查看公钥 把上面的…

Electron 学习笔记

目录 一、安装和启动electron 1. 官网链接 2. 根据文档在控制台输入 3. 打包必填 4. 安装electron开发依赖 5. 在开发的情况下打开应用 6. 修改main为main.js,然后创建main.js 7.启动 二、启动一个窗口 1. main.js 2. index.html 3. 隐藏菜单栏 三、其他…