缓冲区设置

news2024/10/5 22:04:21

缓冲区设计

一、简介

在网络通讯中,用户态缓冲区和内核态缓冲区的大小设定对于优化网络性能和确保数据传输可靠性至关重要。下图是网路通讯的内核缓冲区使用情况:
在这里插入图片描述
数据的读写都需要进行系统调用,从用户态切换到内核态去接收数据,结束后需要切换回用户态;
在这里插入图片描述

二、网络数据的传输过程:
  • 发送
    1. 应用程序通过系统调用将用户数据拷贝sk_buff,并放到socket的发送缓冲区中
    2. 网络协议栈从socket法案送缓冲区中取出sk_buffer,并克隆一个新的sk_buffer(用于丢失重传)
    3. 向下依次增加TCP/UDP头部、IP头部、帧头(MAC头)、帧尾,(tcp层进行数据分段、IP层进行数据分片)
    4. 触发软件中断,通知网卡驱动程序有新的网络数据需要发送
    5. 网卡驱动程序从发送队列中取出sk_buffer写到ringbuffer(内存DMA区域)
    6. 网卡发送数据,发送成功后触发硬件中断,释放sk_buffer和ringbuffer没存
    7. 当接收到tcp报文的ack应答后释放sk_buffer
  • 接收
    1. 网卡接收到数据包,通过DMA协处理器将数据写入内存ringbuffer结构中
    2. 网卡向cpu发起硬件中断,cpu收到中断请求,根据中断表查找中断处理函数,进行中断处理
    3. 中断处理函数将屏蔽中断,发起软件中断
    4. 内核ksoftirqd软件中断线程负责软件中断处理,该线程从ringbuffer中逐个取出数据帧到sk_buffer
    5. 从帧头取出ip协议,去掉帧头帧尾
    6. 根据协议五元组找到socket,并将数据取出放到sicket的接收缓冲区中,软件中断处理结束后开启硬件中断
    7. 应用程序通过系统调用将socket中的接收缓冲区的数据拷贝到用户层缓冲区
用户态缓冲区(User-Space Buffer)

用户态缓冲区是指在应用程序地址空间中分配的缓冲区,用于存储待发送或已接收的数据。调整用户态缓冲区的大小可以影响应用程序处理数据的能力,特别是在高吞吐量或低延迟要求的场景中。

  • 在C/C++中,可以通过setsockopt函数来调整TCP或UDP套接字的发送(SO_SNDBUF)和接收(SO_RCVBUF)缓冲区大小。例如:

    1int snd_buff_size = 8192; // 自定义的发送缓冲区大小
    2int rcv_buff_size = 16384; // 自定义的接收缓冲区大小
    3setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &snd_buff_size, sizeof(snd_buff_size));
    4setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcv_buff_size, sizeof(rcv_buff_size));
    
  • 注意,实际设置的缓冲区大小可能会受到操作系统限制,并且可能不是精确设置的值。有时,内核可能会调整至最接近的允许值,通常是用户请求值的两倍。

三、内核态缓冲区(Kernel-Space Buffer)

内核态缓冲区是操作系统内核管理的一部分,用于在网络接口和用户空间之间暂存数据。它的大小直接影响到网络数据包的处理效率,尤其是在网络拥塞或高流量情况下。

  • 对于Linux系统,可以通过修改内核参数来调整某些类型的内核缓冲区大小,例如通过编辑/etc/sysctl.conf文件或使用sysctl命令动态调整。例如,调整网络接收缓冲区的默认最小值和最大值:

    # 动态调整
    sudo sysctl -w net.core.rmem_default=xxxx # 设定默认接收缓冲区大小
    sudo sysctl -w net.core.rmem_max=yyyy    # 设定最大接收缓冲区大小
    
    # 或者永久修改,在/etc/sysctl.conf中添加:
    net.core.rmem_default=xxxx
    net.core.rmem_max=yyyy
    
  • 对于特定设备,如串口,可以通过Linux命令行工具(如stty)或者编程方式来调整其缓冲区大小。

设置原则

  • 缓冲区大小的选择应基于实际应用场景,包括网络带宽、期望的延迟、以及可能遇到的网络拥塞情况。
  • 通常,较大的缓冲区可以减少数据包丢失,但在高流量下可能导致更高的延迟,因为数据在缓冲区中排队等待处理的时间更长。
  • 较小的缓冲区可以降低延迟,但在网络拥塞时更容易导致数据包丢失。
  • 最佳实践是通过测试和监控来确定最适合的缓冲区大小,有时这可能需要多次调整和验证。
四、缓冲区的设计
  • read/write阻塞io,通过阻塞线程的方式等待io就绪
  • reactor网络模型,io多路复用检测多路连接io是否就绪,在事件循环中依次处理操作io
  • proactor网络模型,异步io,内核完成检测io以及操作io,等待完成后向用户层抛出完成通知

以上这几种网络都对用户态的缓冲区设计没有影响

1、设计方案:
  • 定长的buffer

    • 优点:结构简单
    • 缺点:频繁挪动数据;没有扩容和缩容机制
  • 环形缓冲区ringbuffer

    • 优点:环形结构,不需要挪动数据
    • 缺点:空间不连续;没有扩容和缩容机制
      结构设计入下
      在这里插入图片描述
  • chainbuffer

    • 优点:不需要挪动数据,可以实现动态扩容和缩容

      结构设计图如下: 在这里插入图片描述

2、环形缓冲区

下面主要介绍一下ringbufeer,其数据结构为

struct ringbuffer_s {
    uint32_t size;	// 环形结构的大小
    uint32_t tail;	// 尾指针
    uint32_t head;	// 头指针
    uint8_t * buf;	// 数据指针
};

创建环形缓冲区

// 用于将num值扩展大最近比num值大的2^n的值,用于后面计算优化(将取余操作优化为位运算操作)
static inline uint32_t roundup_power_of_two(uint32_t num) {
    if (num == 0) return 2;
    int i = 0;
    for (; num != 0; i++)
        num >>= 1;
    return 1U << i;
}
buffer_t * buffer_new(uint32_t sz) {
    if (!is_power_of_two(sz)) sz = roundup_power_of_two(sz);
    // 创建buffer时大小要加上结构体本身的大小
    buffer_t * buf = (buffer_t *)malloc(sizeof(buffer_t) + sz);
    if (!buf) {
        return NULL;
    }
    buf->size = sz;
    buf->head = buf->tail = 0;
    buf->buf = (uint8_t *)(buf + 1);
    return buf;
}

添加数据

int buffer_add(buffer_t *r, const void *data, uint32_t sz) {
    if (sz > rb_remain(r)) {
        return -1;
    }
    uint32_t i;
    // 当前位置到尾部的空间大小是否满足插入数据的大小
    i = min(sz, r->size - (r->tail & (r->size - 1)));
    // 插入到数据尾部
    memcpy(r->buf + (r->tail & (r->size - 1)), data, i);
    // 剩余的数据插到头部
    memcpy(r->buf, data+i, sz-i);
    r->tail += sz;
    return 0;
}

数据获取移除

// 数据移除只需要移动指针的位置即可
int buffer_remove(buffer_t *r, void *data, uint32_t sz) {
    assert(!rb_isempty(r));
    uint32_t i;
    sz = min(sz, r->tail - r->head);
    i = min(sz, r->size - (r->head & (r->size - 1)));
    // 将数据拷贝到data中
    memcpy(data, r->buf+(r->head & (r->size - 1)), i);
    memcpy(data+i, r->buf, sz-i);
	// 更新数据头指针位置,移除数据
    r->head += sz;
    return sz;
}

数据空间位置调整

// 将数据挪动到头部位置,使得数据保持连续
uint8_t * buffer_write_atmost(buffer_t *r) {
	// 使用位操作代替取余操作,size必须要是2^n
    uint32_t rpos = r->head & (r->size - 1);
    uint32_t wpos = r->tail & (r->size - 1);
    if (wpos < rpos) {
        // 数据不连续,挪动数据,使其保持连续
        uint8_t* temp = (uint8_t *)malloc(r->size * sizeof(uint8_t));
        memcpy(temp, r->buf+rpos, r->size - rpos);
        memcpy(temp+r->size-rpos, r->buf, wpos);
        free(r->buf);
        r->buf = temp;
        return r->buf;
    }
    // 返回数据起始位置
    return r->buf + rpos;
}

专属学习链接:https://xxetb.xetslk.com/s/36yiy3

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

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

相关文章

《市场瞭望》期刊简介及投稿要求

《市场瞭望》是一本由福建日报社&#xff08;福建日报报业集团&#xff09;主办的经济类杂志&#xff0c;创刊于1994年&#xff0c;半月刊&#xff0c;A4纸大小&#xff0c;内文80页&#xff0c;铜版纸全彩印刷&#xff0c;国内外公开发行。 该杂志的邮发代号为--国际刊号ISSN…

韩国职场新趋势:员工拒绝晋升,追求工作与生活的平衡

在当前职场环境中&#xff0c;晋升通常被视为职业生涯发展的重要里程碑。然而&#xff0c;据韩国《今日财经》报道&#xff0c;现代重工工会在今年的劳资谈判中提出了一个令人关注的要求——“拒绝晋升权”。这一要求反映了韩国职场的新趋势&#xff0c;即越来越多的员工对高薪…

C++ Primer Plus第五版+习题重点笔记(p250-300)

第七章 类&#xff08;下&#xff09; clear需要访问Screen的私有成员;而要想令这种访问合法&#xff0c;Screen需要把 window mgr 指定成它的友元 如果一个类指定了友元类&#xff0c;则友元类的成员函数可以访问此类包括非公有成员在内的所有成员 每个类负责控制自己的友元…

9个最佳性能测试工具(2024)

1、前言 性能测试检查软件程序在预期工作负载下的速度、响应时间、可靠性、资源使用情况和可扩展性。性能测试的目的不是发现功能缺陷&#xff0c;而是消除软件或设备中的性能瓶颈。 性能测试为利益相关者提供有关其应用程序的速度、稳定性和可扩展性的信息。更重要的是&…

QSpinBox、QDoubleSpinBox 的使用,进制转换

实现目的 使用QSpinBox、QDoubleSpinBox 实现数量*单价&#xff0c;float结果显示 使用QSpinBox、QDoubleSpinBox 实现进制的转换 拟实现界面 布局 垂直布局、groupBox中为栅格布局 控件进制设置属性 displayIntegerBase 16代表16进制 #include "spinboxexample.h" #…

AI应用中心:搭建上线了,发现出色的人工智能的网站软件

https://aiapp.ai-51.com 1w 个最佳人工智能应用和服务 AI 应用中心拥有丰富的国内外 AI 应用&#xff0c;收录了超过 1w 个出色的人工智能网站和应用&#xff0c;覆盖了 40 多个不同的领域&#xff0c;如 Ai 绘画生成、Ai 文案写作、Ai 视频编辑、Ai 智能营销等。您可以通过我…

python-再求f(x,n)

[题目描述] 已知 用递归函数求解。输入&#xff1a; 第一个数是 &#x1d465;的值&#xff0c;第二个数是 &#x1d45b;的值。&#xff08;&#x1d45b; 为整数&#xff09;输出&#xff1a; 函数值&#xff0c;保留两位小数。样例输入1 1 2 样例输出1 0.40 来源/分类&…

Android Studio 2024.1.1(Koloa)版本 Profiler 工具变动

在 Android Studio 2024.1.1 (Koloa) 版本当中&#xff0c;Profiler 工具终于迎来了重大 UI 更新&#xff08;太感动了&#xff0c;因为之前的 Profiler 工具连接得慢&#xff0c;收集 Trace 信息还很卡&#xff0c;步骤繁琐等&#xff0c;这次更新有了很大的优化&#xff09; …

关于C#导出Word时报错“{00020970-0000-0000-C000-000000000046}加载类型库/DLL 时出错”的解决办法

之前还运行正常的程序&#xff0c;突然发现导出Word的时候会报错&#xff0c;报错内容&#xff1a; System.InvalidCastException:“Unable to cast COM object of type ‘Microsoft.Office.Interop.Word.ApplicationClass’ to interface type ‘Microsoft.Office.Interop.Wor…

[图解]建模相关的基础知识-11

1 00:00:00,700 --> 00:00:05,090 下一个知识点就是函数在集合上的限制 2 00:00:08,290 --> 00:00:10,200 符号可以这样来 3 00:00:10,210 --> 00:00:16,640 F然后一个往下的箭头A 4 00:00:16,650 --> 00:00:19,520 意思就是说F里面的元素 5 00:00:20,120 --&…

两个src案例分享

案例一 文前废话:某天正在刷着**社区的帖子,欣赏着漂亮的小姐姐,突然间评论区的一条评论引起了我的注意,类似于下面这样 这种评论在html标签中代码格式是<a>这是文字</a>这样的 同时评论区XSS漏洞的高发区,想着可能会有操作点 一、发布一个标题有js语句的贴子 二…

24小时售出115万单,夏日瘦身经济开始走什么路线?

随着气温日渐升高&#xff0c;“减肥”二字出现的频率变得越来越高&#xff0c;减肥市场竞争激烈&#xff0c;各大品牌纷纷加大对市场的推广力度。食品、饮品、器械、服饰都在抢占专属份额。 随着消费者对健康减脂的意识提高&#xff0c;对服饰、器械和相关食品的要求也不断提升…

Win10 已解决:系统管理员已阻止你运行此应用

Win10安装msi软件包时出现错误提示如下&#xff1a; 解决 按【winR】快捷键打开运行&#xff0c;输入gpedit.msc回车依次进入”Windows设置“—”安全设置“—”本地策略“–”安全选项“—”用户账户控制&#xff1a;以管理员批准模式运行所有管理员“—双击&#xff0c;设置…

DIY制作耳机壳时使用哪一种胶粘剂性价比最高?

DIY制作耳机壳时使用哪一种胶粘剂性价比最高&#xff1f; 选择性价比最高的胶粘剂需要根据具体的应用场景和需求来确定。不同的胶粘剂有不同的特点和使用范围&#xff0c;因此其性价比也不同。 一般来说&#xff1a; 如果需要快速粘合、透明度高、粘合力强的场景&#xff0c…

C++ SIMD性能优化

// 使用SIMD指令优化的向量加法 //<mmintrin.h> MMX //<xmmintrin.h> SSE //<emmintrin.h> SSE2 //<pmmintrin.h> SSE3 //<tmmintrin.h> SSSE3 //<smmintrin.h> SSE4.1 //<nmmintrin.h> SSE4.2 //<wmmintrin.h> AES //<imm…

微信 小程序应用,页面,组件的生命周期

组件生命周期 组件的生命周期&#xff1a;指的是组件自身的一些钩子函数&#xff0c;这些函数在特定的时间节点时被自动触发 组件的生命周期函数需要在 lifetimes 字段内进行声明 最重要的生命周期是 created attached detached 包含一个组件生命周期流程的最主要时间点 定…

【Python】从0开始的Django基础

Django框架基础 unit01一、Django基础1.1 什么是Django?1.2 安装与卸载1.2.1 Python与Django的版本1.2.2 安装1.2.3 查看Django版本1.2.4 卸载 二、Django项目2.1 概述2.2 创建项目2.3 启动项目2.4 项目的目录结构2.5 配置 三、URL 调度器3.2 定义URL路由3.2 定义首页的路由3.…

大模型太贵?找找自己的原因好吧?

什么&#xff1f; 炼个大模型还嫌贵&#xff1f; 到底哪里贵了&#xff01;&#xff1f; 大模型算力贵&#xff1f;哪里贵了&#xff01;&#xff1f; 争先恐后训练大模型&#xff0c; 搞得现在“算力慌”“一卡难求”&#xff0c; 算力当然水涨船高了! “特供版”GPU又…

vue中axios从content-disposition响应头获取中文名

在Vue中使用axios请求文件时&#xff0c;服务器可能会返回带有Content-Disposition响应头的文件&#xff0c;其中可能包含文件名的编码信息。如果你需要解码这个文件名&#xff0c;可以使用JavaScript的内置URL API来处理。 Java中用于设置HTTP响应头的&#xff0c;通常在Web开…

js中!emailPattern.test(email) 的test是什么意思

test 是 JavaScript 正则表达式&#xff08;RegExp&#xff09;对象的方法之一&#xff0c;用于测试一个字符串是否与正则表达式匹配。正则表达式是一种用于匹配字符串的模式&#xff0c;通常用于验证输入数据、查找和替换文本等。 使用 test 方法 test 方法语法如下&#xf…