0基础学做网站/微信seo什么意思

0基础学做网站,微信seo什么意思,wordpress pre标签,网站制作怎么做下拉菜单文章目录 1. 前言2. skb 数据管理2.1 初始化2.2 数据的插入2.2.1 在头部插入数据2.2.2 在尾部插入数据 2.2 数据的移除 3. 小结 1. 前言 限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。 2. skb 数据管理 数…

文章目录

  • 1. 前言
  • 2. skb 数据管理
    • 2.1 初始化
    • 2.2 数据的插入
      • 2.2.1 在头部插入数据
      • 2.2.2 在尾部插入数据
    • 2.2 数据的移除
  • 3. 小结

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. skb 数据管理

数据结构:

/* include/linux/skbuff.h */struct sk_buff {.../** @len: sk_buff 包含的数据长度(sk_buff::tail - sk_buff::data). *       当在协议层间移动时, @len 会改变: 添加(往下层)或移除(往上层)*		 操作接口 skb_reserve(), skb_put(), skb_push(), skb_pull()*/unsigned int		len,data_len/* 仅用于分片场景下分片(fragment)数据的长度 */;__u16			mac_len/* MAC 头部长度 */,hdr_len;...__be16			protocol; /* ETH_P_IP, ... */__u16			transport_header; /* 传输层数据偏移 */__u16			network_header; /* 网络层数据偏移 */__u16			mac_header; /* MAC/Linker 层数据偏移 */.../* These elements must be at the end, see alloc_skb() for details.  *//** head --> -------------------*         | reserved headroom |* data -->|-------------------|*         |\\\\\\\\\\\\\\\\\\\|*         |\\\\\\\\\\\\\\\\\\\|* tail -->|-------------------|*         |      tailroom     |* end  -->|-------------------|*         |  skb_shared_info  |*         |-------------------|*         |       PAD         |*          -------------------*/sk_buff_data_t		tail; /* 偏移位置: 指向当前数据的尾部,随数据的添加、移除而改变 */sk_buff_data_t		end; /* 偏移位置: 可用数据空间的尾部。end 后还跟有 skb_shared_info */unsigned char		*head, /* 数据指针: 指向可用数据空间数据头部 */*data; /* 数据指针: 指向当前数据开始位置 */unsigned int		truesize; /* sizeof(sk_buff) + size(数据空间大小) + sizeof(skb_shared_info), 由 alloc_skb() 初始化 */refcount_t			users; /* sk_buff 引用计数. skb_get(), kfree_skb() 接口影响 */
};

2.1 初始化

创建 skb 时的初始化:

struct sk_buff *skb;
int frame_len; /* 网卡接收的数据帧长度 */frame_len = ...;
skb = netdev_alloc_skb_ip_align(priv->dev, frame_len);
/* include/linux/skbuff.h */static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,unsigned int length)
{return __netdev_alloc_skb_ip_align(dev, length, GFP_ATOMIC);
}static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,unsigned int length, gfp_t gfp)
{struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);if (NET_IP_ALIGN && skb)skb_reserve(skb, NET_IP_ALIGN); /* 在数据头部保留部分空间 */return skb;
}
/* net/core/skbuff.c */struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,gfp_t gfp_mask)
{struct page_frag_cache *nc;unsigned long flags;struct sk_buff *skb;bool pfmemalloc;void *data;/** 数据长度对齐:* 没有特别定义 NET_SKB_PAD 时,是对齐到 cache 行。*/len += NET_SKB_PAD;.../* skb_shared_info 包含在 skb 的数据(长度)内 */len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); len = SKB_DATA_ALIGN(len);...data = page_frag_alloc(nc, len, gfp_mask); /* 分配 @len 数据空间 */...skb = __build_skb(data, len); /* 用 @len 长度数据 @data 构建 skb */...skb_success:skb_reserve(skb, NET_SKB_PAD); /* 在数据头部保留部分空间 */skb->dev = dev; /* 设定 skb 的 所属的 网卡设备对象 */skb_fail:return skb;
}struct sk_buff *__build_skb(void *data, unsigned int frag_size)
{struct skb_shared_info *shinfo;struct sk_buff *skb;unsigned int size = frag_size ? : ksize(data);/* 创建 skb 对象 */skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);...size -= SKB_DATA_ALIGN(sizeof(struct skb_shared_info));memset(skb, 0, offsetof(struct sk_buff, tail)); /* skb->tail 之前的所有成员清 0 */skb->truesize = SKB_TRUESIZE(size);refcount_set(&skb->users, 1);skb->head = data;skb->data = data;skb_reset_tail_pointer(skb); /* 初始化 tail: 指向数据开始的偏移位置,即 skb->data 所在的偏移位置 */skb->end = skb->tail + size;skb->mac_header = (typeof(skb->mac_header))~0U;skb->transport_header = (typeof(skb->transport_header))~0U;/* make sure we initialize shinfo sequentially */shinfo = skb_shinfo(skb);memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));atomic_set(&shinfo->dataref, 1);return skb;
}

我们用一张图来描述 skb 的初始状态:

在这里插入图片描述

skb 数据管理,主要依靠 tail, end, head, data 这几个成员。从图中可见,在初始时:

head: 指向数据的开始位置。
data: 指向可用数据的开始位置,跳过了头部保留空间。
tail: 当前已填充数据的结尾位置偏移。
end: 数据可用空间结尾位置偏移。

2.2 数据的插入

数据插入位置可以是 头部尾部

2.2.1 在头部插入数据

头部插入数据,首先通过 *skb_push() 系列 API 按插入数据长度移动数据位置指针,然后执行数据拷贝。

如进行 IP 数据分片时:

int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,int (*output)(struct net *, struct sock *, struct sk_buff *))
{...skb_reset_transport_header(frag); /* 设置 传输层 数据偏移位置 */__skb_push(frag, hlen); /* 往后移动数据指针,在头部为 网络层协议头(L3) 划分一部分空间 */skb_reset_network_header(frag); /* 设置 网络层 数据偏移位置 */memcpy(skb_network_header(frag), iph, hlen); /* 在 头部 插入 网络层 数据 */...
}
/* include/linux/skbuff.h *//* 设置 传输层(L4) TCP/UDP 头部数据偏移位置 */
static inline void skb_reset_transport_header(struct sk_buff *skb)
{skb->transport_header = skb->data - skb->head;
}/** 从头部增加 @len 长度数据后调用: * . skb->data 后退 @len 个位置 (skb->data -= len)* . skb->len 增大 @len*/
void *skb_push(struct sk_buff *skb, unsigned int len);
static inline void *__skb_push(struct sk_buff *skb, unsigned int len)
{skb->data -= len;skb->len  += len;return skb->data;
}/* 设置 网络层(L3) IP 头部数据偏移位置 */
static inline void skb_reset_network_header(struct sk_buff *skb)
{skb->network_header = skb->data - skb->head;
}/* 返回 网络层 (L3) IP 头部位置 (struct ip_header *) */
static inline unsigned char *skb_network_header(const struct sk_buff *skb)
{return skb->head + skb->network_header;
}

从这里的示例代码可以看到,在头部插入数据,分为两步:

1. 通过 __skb_push() 移动数据指针
2. 然后再将数据拷贝到指定位置

可见,*skb_push() 系列 API 只会移动数据指针,并不会做数据拷贝操作。

2.2.2 在尾部插入数据

尾部插入数据,首先执行数据拷贝,然后通过 *skb_put() 系列 API 按拷贝的数据长度移动 skb 数据位置指针。

如网卡接收数据时:

static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
{.../* 分配 skb 缓冲(细节见前面分析) */     skb = netdev_alloc_skb_ip_align(priv->dev, frame_len);/* 拷贝接收的数据(RING BUFFE 中的数据)到 skb 缓冲 */skb_copy_to_linear_data(skb,rx_q->rx_skbuff[entry]->data,frame_len);skb_put(skb, frame_len); /* 移动数据指针 */...
}
/* include/linux/skbuff.h */static inline void skb_copy_to_linear_data(struct sk_buff *skb,const void *from,const unsigned int len)
{memcpy(skb->data, from, len);
}#ifdef NET_SKBUFF_DATA_USES_OFFSET
static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
{return skb->head + skb->tail;
}static inline void skb_reset_tail_pointer(struct sk_buff *skb)
{skb->tail = skb->data - skb->head;
}static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
{skb_reset_tail_pointer(skb);skb->tail += offset;
}#else /* NET_SKBUFF_DATA_USES_OFFSET */
static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
{return skb->tail;
}static inline void skb_reset_tail_pointer(struct sk_buff *skb)
{skb->tail = skb->data;
}static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
{skb->tail = skb->data + offset;
}#endif /* NET_SKBUFF_DATA_USES_OFFSET */
/* net/core/skbuff.c *//** 增加数据长度,在【尾部】增加数据时使用: * . 前进数据【尾部偏移】 skb->tail += len* . 增大数据长度 skb->len += len* 返回: 数据旧的尾部位置数据指针。*/
void *skb_put(struct sk_buff *skb, unsigned int len)
{void *tmp = skb_tail_pointer(skb);SKB_LINEAR_ASSERT(skb);skb->tail += len;skb->len  += len;if (unlikely(skb->tail > skb->end)) /* 超出了数据尾部空间 */skb_over_panic(skb, len, __builtin_return_address(0));return tmp;
}
EXPORT_SYMBOL(skb_put);

2.2 数据的移除

处于效率的考虑,skb 数据的移除,并不是真的移除,而是仅仅移动数据指针位置。通过 *skb_pull() 系列 API 执行数据的移除:

/* net/core/skbuff.c */void *skb_pull(struct sk_buff *skb, unsigned int len)
{return skb_pull_inline(skb, len);
}
EXPORT_SYMBOL(skb_pull);
/* include/linux/skbuff.h *//** 从头部拉取 @len 长度数据后调用: * . skb->data 前进 @len 个位置 (skb->data += len)* . skb->len 减小 @len*/
static inline void *skb_pull_inline(struct sk_buff *skb, unsigned int len)
{return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
}/** 从头部拉取 @len 长度数据后调用: * . skb->data 前进 @len 个位置 (skb->data += len)* . skb->len 减小 @len*/
void *skb_pull(struct sk_buff *skb, unsigned int len);
static inline void *__skb_pull(struct sk_buff *skb, unsigned int len)
{skb->len -= len;BUG_ON(skb->len < skb->data_len);return skb->data += len;
}

3. 小结

本文简单的对 skb 数据管理的最基本情形 - 线性数据的插入删除 - 做了描述,事实上,skb 的数据的管理,远比这个要更复杂,譬如 IP 分片的非线性数据管理skb_shared_info 的管理等等,以后有机会再和大家一起探讨。

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

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

相关文章

批量给 Excel 添加或删除密码保护|Excel 批量设置打开密码和只读密码

我们在将 Excel 文档发送给第三方或者进行存档的时候&#xff0c;对 Excel 文档添加密码保护是非常重要的一个操作。添加保护后的 Excel 文档。就只能有相应权限的用户才能够打开或者编辑操作。尤其是当我们 Excel 文档中内容非常敏感非常重要的时候&#xff0c;添加保护就显得…

蓝耘MaaS平台:阿里QWQ应用拓展与调参实践

摘要&#xff1a;本文深入探讨了蓝耘MaaS平台与阿里QWQ模型的结合&#xff0c;从平台架构、模型特点到应用拓展和调参实践进行了全面分析。蓝耘平台凭借其强大的算力支持、弹性资源调度和全栈服务&#xff0c;为QWQ模型的高效部署提供了理想环境。通过细化语义描述、调整推理参…

使用 Docker 部署前端项目全攻略

文章目录 1. Docker 基础概念1.1 核心组件1.2 Docker 工作流程 2. 环境准备2.1 安装 Docker2.2 验证安装 3. 项目配置3.1 项目结构3.2 创建 Dockerfile 4. 构建与运行4.1 构建镜像4.2 运行容器4.3 访问应用 5. 使用 Docker Compose5.1 创建 docker-compose.yml5.2 启动服务5.3 …

springboot集成flink实现DM数据库同步到ES

前言 今天分享的其实是一个面试上机方案&#xff0c;就是监测DM数据库数据&#xff0c;同步到ES&#xff0c;使用flink实现。基本套路&#xff0c;其实也没啥好说的&#xff0c;非要说也就是&#xff0c;国家队还是很多不跟你玩啊&#xff0c;虽然flink有阿里在背后&#xff0c…

【蓝桥杯】24省赛:数字串个数

思路 本质是组合数学问题&#xff1a; 9个数字组成10000位数字有9**10000可能 不包括3的可能8**10000 不包括7的可能8**10000 既不包括3也不包括77**10000 根据容斥原理&#xff1a;结果为 9 ∗ ∗ 10000 − 8 ∗ ∗ 10000 − 8 ∗ ∗ 10000 7 ∗ ∗ 10000 9**10000 - 8**10…

Unity开发中对象池设计与使用

一、设计目的 为了避免频繁创建和销毁对象&#xff08;例如 UI 元素、事件对象等&#xff09;带来的内存分配和垃圾回收压力&#xff0c;可以使用对象池来管理对象来提高游戏的性能&#xff0c;避免游戏卡顿。 二、代码实现 public interface IRecycle {/// <summary>…

JVM并发编程AQSsync锁ReentrantLock线程池ThreadLocal

并发编程2 synchronized锁实现**AQS****ReentrantLock实现****JUC 常用类**池的概念 ThreadLocalThreadLocal原理内存泄露强引用:软引用弱引用虚引用ThreadLocal内存泄露 synchronized锁实现 synchronized是一个关键字,实现同步,还需要我们提供一个同步锁对象,记录锁状态,记录…

【JavaEE】网络原理之初识

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

操作系统-八股

进程基础&#xff1a; 进程定义&#xff1a;运行中的程序&#xff0c;有独立的内存空间和地址&#xff0c;是系统进行资源调度和分配的基本单位。 并发&#xff0c;并行 并发就是单核上面轮询&#xff0c;并行就是同时执行&#xff08;多核&#xff09;&#xff1b; 进程上下…

chrome浏览器插件拓展捕获页面的响应体内容

因为chrome extension官方没有的直接获取响应体的方法&#xff0c;所以需要自己实现方法来获取&#xff0c;实现的方式有很多种&#xff0c;这是记录的第二种&#xff0c;第一种就是使用vconsole来实现&#xff0c;vconsole是一个开源框架&#xff0c;一个轻量、可拓展、针对手…

沐数科技数据开发岗笔试题2025

描述性统计 标准差 答案: A 解析: 标准差 衡量数据集中数值变化或离散程度的一种度量。它反映了数据集中的各个数值与数据集的平均值&#xff08;均值&#xff09;之间的偏离程度。标准差越大&#xff0c;表明数据的分布越分散&#xff1b;标准差越小&#xff0c;表明数据…

Qt-ZMQ的使用补充(pub-sub)

之前写过一篇Qt使用ZMQ的博客Qt网络编程-ZMQ的使用&#xff0c;本文是其的补充部分。 Linux上编译使用 首先这次实在Linux上进行演示&#xff0c;下载zmq源码&#xff0c;安装cmake&#xff0c;使用cmake进行编译。下载之后解压&#xff1a; 输入命令&#xff1a; cd ..mkdi…

记录致远OA服务器硬盘升级过程

前言 日常使用中OA系统突然卡死&#xff0c;刷新访问进不去系统&#xff0c;ping服务器地址正常&#xff0c;立马登录服务器检查&#xff0c;一看磁盘爆了。 我大脑直接萎缩了&#xff0c;谁家OA系统配400G的空间啊&#xff0c;过我手的服务器没有50也是30台&#xff0c;还是…

[测试]自动化的概念 及使用Selenium实现Web自动化测试

文章目录 1. 自动化1.1 自动化概念1.2 自动化分类1.2.1 接口自动化1.2.2 UI自动化 1.3 自动化测试金字塔 2. Web自动化测试2.1 驱动 3. Selenium3.1 一个简单的Web自动化示例3.2 Selenium 驱动 浏览器的工作原理 1. 自动化 1.1 自动化概念 自动化是指自动地代替人的行为完成…

Python教程(三):类对象、闭包、装饰器、类型注解、MRO

Python总结&#xff08;三&#xff09; 本系列其他教程&#xff1a; Python教程(一)&#xff1a;基本语法、流程控制、数据容器 Python教程(二)&#xff1a;函数、异常、模块&包、文件读取、常用模块 文章目录 Python总结&#xff08;三&#xff09;一、类&对象1.1 成…

什么是 HTML?

HTML 是用来描述网页的一种语言。 HTML 指的是超文本标记语言: HyperText Markup LanguageHTML 不是一种编程语言&#xff0c;而是一种标记语言标记语言是一套标记标签 (markup tag)HTML 使用标记标签来描述网页HTML 文档包含了HTML 标签及文本内容HTML文档也叫做 web 页面 HT…

如何用AI制作PPT,轻松实现高效演示

如何用AI制作PPT&#xff0c;轻松实现高效演示&#xff01;在今天这个快节奏的时代&#xff0c;我们的工作方式越来越依赖智能工具。而当涉及到演示文稿时&#xff0c;传统的PPT制作方式往往繁琐且耗时。很多人一提到制作PPT就头大&#xff0c;特别是在内容需要多次修改、调整布…

Canoe Panel基础功能介绍

文章目录 一、新建 Panel 面板二、添加 Panel 面板三、删除 Panel 面板四、Panel视图&#xff08;views&#xff09;五、控件布局1. 对齐布局2. 控件大小布局 六、Panel 属性设置1. 设置背景色和背景图片2. 调整 Panel 画布大小 提示&#xff1a;如何使用 Panel 面板参考 CANoe…

超声重建,3D重建 超声三维重建,三维可视化平台 UR 3D Reconstruction

1. 超声波3D重建技术的实现方法与算法 技术概述 3D超声重建是一种基于2D超声图像生成3D体积数据的技术&#xff0c;广泛应用于医学影像领域。通过重建和可视化三维结构&#xff0c;3D超声能够显著提高诊断精度和效率&#xff0c;同时减少医生的脑力负担。本技术文档将详细阐述…

2.2 企业级ESLint/Prettier规则定制

文章目录 1. 为什么需要企业级代码规范2. 工具选型对比3. 完整配置流程3.1 项目初始化3.2 ESLint深度配置3.3 Prettier精细配置3.4 解决规则冲突4. 高级定制方案4.1 自定义ESLint规则4.2 扩展Prettier插件5. 团队协作策略5.1 配置共享方案5.2 版本控制策略6. CI/CD集成7. 常见问…