【Nova】nova-scheduler过滤称重

2023-05-16

在上一篇“ nova-scheduler调度过程分析”中,对过滤称重的过程一笔带过了,这篇着重介绍一下。

首先,我们声明一下host为主机,node为节点,在OpenStack中一个host可以运行多个node或者nova-compute服务。

第一步,过滤filter,通过HostManager的get_filtered_hosts实现:

选取Icehouse版本支持的部分主机过滤器进行简要说明:

RetryFilter -> 如果主机已经尝试被调度了,那么过滤不通过

AvailabilityZoneFilter -> 我们可以根据物理位置对主机划分“可用域”, 如果创建虚拟机实例时指定了availability_zone,而主机又不在

        该availability_zone中,那么过滤不通过

RamFilter -> 如果主机的可用内存不足以提供虚拟机实例需要的内存,那么过滤不通过

ComputeFilter -> 如果主机的计算服务被禁用掉或者down掉(一定时间内没有收到心跳包), 那么过滤不通过

ComputeCapabilitiesFilter -> 创建虚拟机实例时可以指定一些额外的要求,如果主机的能力不满足这些要求,那么过滤不通过

ImagePropertiesFilter -> 我们可以给镜像创建属性,譬如在镜像属性指定架构、hypervisor和虚拟机模式,如果主机不支持这些属性的虚拟机,那么过滤不通过

ServerGroupAntiAffinityFilter、ServerGroupAffinityFilter ->给定一个实例组,那么可以获取运行实例成员的主机集合,如果主机

       在/不在这个主机集合里,那么过滤不通过


# nova-scheduler默认的过滤器列表
cfg.ListOpt('scheduler_default_filters',
            default=[
              'RetryFilter',
              'AvailabilityZoneFilter',
              'RamFilter',
              'ComputeFilter',
              'ComputeCapabilitiesFilter',
              'ImagePropertiesFilter',
              'ServerGroupAntiAffinityFilter',
              'ServerGroupAffinityFilter',
              ],
            help='Which filter class names to use for filtering hosts '
                  'when not specified in the request.'),


# 过滤器基类
class BaseFilter(object):

    def _filter_one(self, obj, filter_properties):
        return True

    def filter_all(self, filter_obj_list, filter_properties):
        for obj in filter_obj_list:
            if self._filter_one(obj, filter_properties):
                yield obj

    run_filter_once_per_request = False
    # 我们可以一次创建多个同类型的实例, 每个实例我们都需要对主机进行一次过滤称重操作,
    # 有些过滤器类只需要在针对第一个实例的过滤过程中运行一次即可, 之后的实例就不再运行
    def run_filter_for_index(self, index):
        if self.run_filter_once_per_request and index > 0:
            return False
        else:
            return True


# 主机过滤器基类
class BaseHostFilter(filters.BaseFilter):
    def _filter_one(self, obj, filter_properties):
        return self.host_passes(obj, filter_properties)

    def host_passes(self, host_state, filter_properties):
        raise NotImplementedError()
        

# 举例: 磁盘过滤器
class DiskFilter(filters.BaseHostFilter):

    def host_passes(self, host_state, filter_properties):

        # 求出创建虚拟机实例所需的磁盘大小
        instance_type = filter_properties.get('instance_type')
        requested_disk = (1024 * (instance_type['root_gb'] +
                                 instance_type['ephemeral_gb']) +
                         instance_type['swap'])

        # 主机的当前可用磁盘大小
        free_disk_mb = host_state.free_disk_mb
        # 主机的总物理磁盘大小
        total_usable_disk_mb = host_state.total_usable_disk_gb * 1024

        # disk_allocation_ratio是总虚拟机实例磁盘/物理磁盘的比率, 默认是1.0;
        # 我们创建一个硬盘大小为60GB的虚拟机实例, 它并不会立刻占用60GB的物理磁盘;
        # 因此, 我们可能在1000GB的物理硬盘上, 创建30个硬盘大小为60GB的虚拟机实例,
        # 这完全是可以的, 只是存在磁盘爆满的情况; 所以这个disk_allocation_ratio我们
        # 可以根据具体应用场景酌情设置高一些
        disk_mb_limit = total_usable_disk_mb * CONF.disk_allocation_ratio
        # 当前已使用硬盘大小
        used_disk_mb = total_usable_disk_mb - free_disk_mb
        # 可用虚拟机实例磁盘大小
        usable_disk_mb = disk_mb_limit - used_disk_mb

        # 当可用虚拟机实例磁盘<创建虚拟机实例所需的磁盘大小时, 我们认为不能让实例落在该主机上
        if not usable_disk_mb >= requested_disk:
            LOG.debug(_("%(host_state)s does not have %(requested_disk)s MB "
                    "usable disk, it only has %(usable_disk_mb)s MB usable "
                    "disk."), {'host_state': host_state,
                               'requested_disk': requested_disk,
                               'usable_disk_mb': usable_disk_mb})
            return False

        # 更新主机的状态信息
        disk_gb_limit = disk_mb_limit / 1024
        host_state.limits['disk_gb'] = disk_gb_limit
        return True


class BaseFilterHandler(loadables.BaseLoader):

    def get_filtered_objects(self, filter_classes, objs,
            filter_properties, index=0):
        list_objs = list(objs)
        LOG.debug(_("Starting with %d host(s)"), len(list_objs))
        for filter_cls in filter_classes:
            cls_name = filter_cls.__name__
            # 创建过滤器类实例
            filter = filter_cls()

            # 判断该过滤器在当前index下是否需要运行
            if filter.run_filter_for_index(index):
                # 对每个list_obj进行_filter_one过滤, _filter_one实际会调用host_passes进行真正的过滤操作
                # 因此, 每个过滤器类只需要继承BaseHostFilter类并实现host_passes方法即可,
                # 这里会返回一个生成器对象
                objs = filter.filter_all(list_objs,
                                               filter_properties)
                if objs is None:
                    LOG.debug(_("Filter %(cls_name)s says to stop filtering"),
                          {'cls_name': cls_name})
                    return
                list_objs = list(objs)
                if not list_objs:
                    # 如果在该过滤器运行之后,没有list_obj通过过滤, 
                    # 那么就不需要运行剩余的过滤器了
                    LOG.info(_("Filter %s returned 0 hosts"), cls_name)
                    break
                LOG.debug(_("Filter %(cls_name)s returned "
                            "%(obj_len)d host(s)"),
                          {'cls_name': cls_name, 'obj_len': len(list_objs)})
        # 返回最终通过所有过滤的list_obj
        return list_objs


class HostManager(object):

    # 返回filter_cls_names指定的过滤器列表
    def _choose_host_filters(self, filter_cls_names):
        if filter_cls_names is None:
        # 如果filter_cls_names未空,那么就返回配置选项scheduler_default_filters中指定的过滤器列表
            filter_cls_names = CONF.scheduler_default_filters
        if not isinstance(filter_cls_names, (list, tuple)):
            filter_cls_names = [filter_cls_names]
        # 返回所有可用的过滤器名称和对应的过滤器类
        # 过滤器采用了插件模式,我们可以自定义过滤器,只需要将文件放入nova/scheduler/filters下面,
        # 那么就可以通过配置选项scheduler_default_filters来使用其中的过滤器
        # 每当nova-scheduler开始运行, 它就会自动在该目录下加载过滤器
        cls_map = dict((cls.__name__, cls) for cls in self.filter_classes)
        
        # 我们可能会因为手误配置了不存在的调度器名, 那么下面就是对要使用的过滤器进行验证,
        # 以杜绝这种错误的发生
        good_filters = []
        bad_filters = []
        for filter_name in filter_cls_names:
            if filter_name not in cls_map:
                bad_filters.append(filter_name)
                continue
            good_filters.append(cls_map[filter_name])
        if bad_filters:
            msg = ", ".join(bad_filters)
            # 如果要使用的调度器不存在,就抛出异常
            raise exception.SchedulerHostFilterNotFound(filter_name=msg)
        # 返回要使用的过滤器类
        return good_filters

    # 对参数hosts中的所有主机进行过滤,返回通过所有过滤条件的主机
    def get_filtered_hosts(self, hosts, filter_properties,
            filter_class_names=None, index=0):

        # 从host_map中去除hostname在hosts_to_ignore中的主机
        def _strip_ignore_hosts(host_map, hosts_to_ignore):
            ignored_hosts = []
            for host in hosts_to_ignore:
                for (hostname, nodename) in host_map.keys():
                    if host == hostname:
                        del host_map[(hostname, nodename)]
                        ignored_hosts.append(host)
            ignored_hosts_str = ', '.join(ignored_hosts)
            msg = _('Host filter ignoring hosts: %s')
            LOG.audit(msg % ignored_hosts_str)

        # 从host_map中去除hostname不在hosts_to_force中的主机
        def _match_forced_hosts(host_map, hosts_to_force):
            forced_hosts = []
            for (hostname, nodename) in host_map.keys():
                if hostname not in hosts_to_force:
                    del host_map[(hostname, nodename)]
                else:
                    forced_hosts.append(hostname)
            if host_map:
                forced_hosts_str = ', '.join(forced_hosts)
                msg = _('Host filter forcing available hosts to %s')
            else:
                forced_hosts_str = ', '.join(hosts_to_force)
                msg = _("No hosts matched due to not matching "
                        "'force_hosts' value of '%s'")
            LOG.audit(msg % forced_hosts_str)

        # 从host_map中去除nodenames不在nodes_to_force中的主机
        def _match_forced_nodes(host_map, nodes_to_force):
            forced_nodes = []
            for (hostname, nodename) in host_map.keys():
                if nodename not in nodes_to_force:
                    del host_map[(hostname, nodename)]
                else:
                    forced_nodes.append(nodename)
            if host_map:
                forced_nodes_str = ', '.join(forced_nodes)
                msg = _('Host filter forcing available nodes to %s')
            else:
                forced_nodes_str = ', '.join(nodes_to_force)
                msg = _("No nodes matched due to not matching "
                        "'force_nodes' value of '%s'")
            LOG.audit(msg % forced_nodes_str)

        # 获取filter_class_names指定的过滤器类列表
        filter_classes = self._choose_host_filters(filter_class_names)
        ignore_hosts = filter_properties.get('ignore_hosts', [])
        force_hosts = filter_properties.get('force_hosts', [])
        force_nodes = filter_properties.get('force_nodes', [])

        if ignore_hosts or force_hosts or force_nodes:
            # 我们不能假设host是唯一的,因为一个host可能运行多个nodes
            name_to_cls_map = dict([((x.host, x.nodename), x) for x in hosts])
            if ignore_hosts:
                # 从name_to_cls_map中去除hostname在ignore_hosts中的host
                _strip_ignore_hosts(name_to_cls_map, ignore_hosts)
                if not name_to_cls_map:
                    return []

            if force_hosts:
                # 从name_to_cls_map中去除hostname不在force_hosts中的host
                _match_forced_hosts(name_to_cls_map, force_hosts)
            if force_nodes:
                # # 从name_to_cls_map中去除nodename不在force_nodes中的host
                _match_forced_nodes(name_to_cls_map, force_nodes)
            if force_hosts or force_nodes:
                # 当我们强制了虚拟机要落在哪些host或node上, 就可以跳过过滤过程
                if name_to_cls_map:
                    return name_to_cls_map.values()
            hosts = name_to_cls_map.itervalues()
        
        # 对hosts使用filter_classes中的过滤器进行过滤, 返回通过过滤的主机列表
        return self.filter_handler.get_filtered_objects(filter_classes,
                hosts, filter_properties, index)


第二步,称重weigh,通过HostManager的get_weighed_hosts实现, 为什么要称重呢?我们可能有多个主机通过过滤filter,那我们怎么决定实例落在哪个主机上了,这就是称重的作用,帮助我们对这些主机进行排序, 以选取出相对最优的主机。

Icehouse版本支持的称重器就以下2种:

RAMWeigher -> 内存称重器, 可用内存越多,重量越重

MetricsWeigher -> 指标称重器, 可以通过配置的形式指定主机的多种指标和比率, 将这些指标结合起来进行称重

我曾经因为需要, 自己写过VCPU称重器,方法很简单,但是对于权重的选择要把握好

# 称重目标类
class WeighedObject(object):

    def __init__(self, obj, weight):
        self.obj = obj
        self.weight = weight

    def __repr__(self):
        return "<WeighedObject '%s': %s>" % (self.obj, self.weight)


# 称重器抽象基类
@six.add_metaclass(abc.ABCMeta)
class BaseWeigher(object):
    minval = None
    maxval = None

    def weight_multiplier(self):
        return 1.0

    @abc.abstractmethod
    def _weigh_object(self, obj, weight_properties):

    def weigh_objects(self, weighed_obj_list, weight_properties):
        weights = []
        for obj in weighed_obj_list:
            # 对obj.obj进行称重
            weight = self._weigh_object(obj.obj, weight_properties)
            
            # 记录和更新重量的最大最小值, 方便进行归一化
            if self.minval is None:
                self.minval = weight
            if self.maxval is None:
                self.maxval = weight

            if weight < self.minval:
                self.minval = weight
            elif weight > self.maxval:
                self.maxval = weight

            weights.append(weight)

        return weights


# 举例: 内存称重器
# 每个称重器只要实现_weigh_object即可, weight_multiplier可根据情况进行覆盖
class RAMWeigher(weights.BaseHostWeigher):
    minval = 0

    def weight_multiplier(self):
        # 返回配置的内存称重权重, 默认为1.0
        return CONF.ram_weight_multiplier

    def _weigh_object(self, host_state, weight_properties):
        # 返回主机的可用内存大小, 内存越大, 优先级越高;
        # 如果我们希望越小优先级越高, 可通过乘以-1实现
        return host_state.free_ram_mb


# 称重处理器基类
class BaseWeightHandler(loadables.BaseLoader):
    object_class = WeighedObject

    def get_weighed_objects(self, weigher_classes, obj_list,
            weighing_properties):

        if not obj_list:
            return []

        # 将要称重的object封装进WeighedObject里, weight为0.0 
        weighed_objs = [self.object_class(obj, 0.0) for obj in obj_list]
        for weigher_cls in weigher_classes:
            # 实例化称重器
            weigher = weigher_cls()
            # 对weighed_objs逐个进行称重, 并返回weights列表
            weights = weigher.weigh_objects(weighed_objs, weighing_properties)

            # 对weights进行归一化, 让每个weight处于[0.0,1.0]之间
            # 为什么要这样做呢?我们不能让称重元素的重量过多的影响称重结果;
            # 假设我们要对主机的内存、硬盘进行称重, 一般主机的内存会比硬盘小很多, 譬如内存为128GB, 硬盘为2048GB;
            # 如果我们不进行归一化, 由于硬盘和内存的大小相差较大, 导致内存的称重对称重结果影响微乎其微, 甚至毫无作用;
            # 我们可以通过归一化抹平不同称重元素之间的差异性, 而通过权重来指定它们的重要性
            weights = normalize(weights,
                                minval=weigher.minval,
                                maxval=weigher.maxval)

            for i, weight in enumerate(weights):
                obj = weighed_objs[i]
                # 更新obj的重量
                # weight_multiplier方法返回的是该称重器的权重
                # 我们可以根据实际需要, 为不同称重器指定不同的权重, 一般来说相对重要的称重器权重更高
                obj.weight += weigher.weight_multiplier() * weight

        # 对称重目标列表按照重量的大小进行降序排列
        # 在OpenStack中重量越大, 意味着主机的优先级越高
        return sorted(weighed_objs, key=lambda x: x.weight, reverse=True)


# 主机称重处理器
class HostWeightHandler(weights.BaseWeightHandler):
    object_class = WeighedHost

    def __init__(self):
        super(HostWeightHandler, self).__init__(BaseHostWeigher)


class HostManager(object):

    def __init__(self):
        ...
        # 创建主机称重处理器实例
        self.weight_handler = weights.HostWeightHandler()
        # 同过滤器一样, 称重器也是采用了插件模式, 我们可以自定义称重器,只需要将文件放入nova/scheduler/weights下面;
        # 这里用于获取和加载该目录下的称重器类
        self.weight_classes = self.weight_handler.get_matching_classes(
                CONF.scheduler_weight_classes)

    def get_weighed_hosts(self, hosts, weight_properties):
        # 这里调用的是BaseWeightHandler中的get_weighed_objects方法;
        # 对hosts使用weight_classes中的称重器进行称重, 返回称重后的有序主机列表
        return self.weight_handler.get_weighed_objects(self.weight_classes,
                hosts, weight_properties)



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Nova】nova-scheduler过滤称重 的相关文章

  • Springboot使用定时任务scheduler详解

    目录 认识示例代码定时任务 调度任务开启调度添加定时任务以固定延迟执行定时任务 fixedDelay以固定速率执行定时任务 fixedRate延迟第一次初始化 initialDelay以 ISO 时间格式指定间隔 fixedRateStri
  • Nsight Compute(NCU) Scheduler Statistics 数据解读

    本文内容主要参考YT上的这个视频 xff1a https www youtube com watch v 61 nYSdsJE2zMs Warp硬件架构介绍 以Volta架构为例 xff0c 每个SM有4个Warp Scheduler xf
  • 【Nova】nova-scheduler过滤称重

    在上一篇 nova scheduler调度过程分析 中 xff0c 对过滤称重的过程一笔带过了 xff0c 这篇着重介绍一下 首先 xff0c 我们声明一下host为主机 xff0c node为节点 xff0c 在OpenStack中一个h
  • Spring 定时器 No qualifying bean of type [org.springframework.scheduling.TaskScheduler] is defined

    最近项目里面 用了spring的定时任务 一直以来 项目运行的不错 定时器也能正常使用 可是 今天启动项目测试的时候 盯着启动Log看了一阵子 突然间发现 启动的Log中居然有一个异常 虽然一闪而过 但是那熟悉的异常格式还是让我浑身一颤 这
  • App Engine - 太多打开的实例

    我的应用程序在 App Engine Java SDK 上运行 从今天早上开始 我注意到打开的实例没有处理新请求 而是启动了新的 Frontent 实例 所以现在我有大约 250 个开放实例 比平时多得多 此外 实例正在版本 1 9 5 上
  • SMP调度在Linux内核中如何工作? (ARM架构)

    在Linux中 当经过特定时间量时 调度程序将被触发 据我了解 计时器触发一个中断 进而触发对schedule 在SMP系统中 我在 Understanding the Linux Kernel 一书中读到 每个处理器都独立运行schedu
  • 可以在触发器内动态创建 JOB 吗?

    该触发器的执行失败 它编译但一旦我执行指定的插入 gt 错误 create or replace TRIGGER AFT INSERT TMP TBL AFTER INSERT ON TMP TBL REFERENCING OLD AS O
  • Linux 上的 pthreads 是如何被调度程序看到的

    我有一个关于 Linux 上 pthread 实现的问题 假设一个进程有5个线程 现在调度程序如何看到这些线程 或根本看不到 例如当调度程序被调用时 它是否只调度主进程 然后主进程有责任在每个线程之间进行调度 或者是另一种方式 调度程序调度
  • 如何使用c#实现加权循环?

    如果我有一些服务器 192 168 100 1 192 168 100 2 192 168 100 3 192 168 100 4 它们的权重为 5 1 2 3 我想实现负载均衡 但是如何使用C 实现加权循环 假设你有服务器a b c d
  • 寻找有限状态机的不同调度算法的比较

    是否有任何好的资源 书籍 网站 可以对没有操作系统的嵌入式系统中的有限状态机 FSM 的不同调度算法进行很好的比较 我正在设计一个简单的嵌入式网络服务器 没有操作系统 我想知道用于安排系统中发生的不同事件的处理的各种方法 例如 如果两个事件
  • 对于彩票调度程序来说,比 LCG 更好的(伪)随机数生成器是什么?

    我想设计一个彩票调度程序 我需要一个非常好的 伪 随机数生成器 类似于 LCG 但我想知道是否还有其他更好的选择 我专门寻找用 C 编写的随机生成器 LCG代码 unsigned long lcg rand unsigned long a
  • 在heroku上使用node.js开发时钟和workers

    我正在开发一项服务 需要每五分钟为不同的用户分析来自社交媒体网络的数据 我正在使用 node js 开发它 并将在 Heroku 上实现它 根据本文 https devcenter heroku com articles scheduled
  • Django 中的 Apscheduler Job 执行两次

    计划的作业执行两次 差异以纳秒为单位 我有一个任务如下task py def print hello print time gt datetime datetime now print hello def print world print
  • 如何说服 powershell(通过任务计划程序运行)找到我的网络驱动器?

    我在 Windows 7 上有一个简单的 powershell 脚本 但无法正常工作 这在 XP 上不是问题 get psdrive 当我直接运行它时 我得到 Name Used GB Free GB Provider Root A Fil
  • sched_getcpu() 相当于 OS X 吗?

    在 OS X 上 有没有办法找出线程正在哪个 CPU 上运行 Linux 的等效函数是调度获取CPU http man7 org linux man pages man3 sched getcpu 3 html 获取当前处理器编号 http
  • Go 调度程序和 CGO:请解释一下这种行为差异吗?

    我想知道这样做的实施原因 package main func main c make chan struct go func print a for go func print b for go func print c c lt stru
  • Pytest 可以在预先安排的时间运行吗?

    我正在使用 pytest 使用 python3 脚本运行我的测试 如下所示 pytest s test file py tee a myoutput log 有用 现在我想在每天的特定时间运行它 我尝试从 Linux 控制台 crontab
  • 在 win 7 任务计划程序中顺序运行批处理文件

    我有 2 个批处理文件作为单个任务中的 操作 第一个使用 Microsoft Security Essentials 扫描病毒 第二个让计算机进入睡眠状态 问题是 当任务运行时 似乎两个批处理文件同时运行 也就是说 我可以看到病毒扫描的开始
  • javaquartz从计划的作业中获取所有详细信息

    我有一个包含多个作业的调度程序 我希望能够显示调度程序中的所有活动作业 我的意思是我想显示每个作业何时被触发 这是我的代码 sched start JobDetail job newJob Jobs class withIdentity j
  • VxWorks调度程序如何执行?

    想知道如何调用调度程序以便它可以切换任务 即使是抢占式调度或循环调度 调度程序也应该参与其中以进行任何类型的任务切换 假设一个低优先级任务有一个无限循环 调度程序什么时候介入并切换到更高优先级的任务 查询是 1 谁调用调度器 在VxWork

随机推荐

  • GitLab 使用Tortoisegit询问“git@192.168.1.18‘s password“问题解决

    现象如下 xff1a 使用TortoiseGit去拉本地GitLab上建立的项目时 xff0c 一直提示输入密码 xff08 如下图 xff09 xff0c 这个密码又没有指定用户名 xff0c 就算你输入你用户名的密码也是失败 但是很诡异
  • 二代身份证读写器原理及开发

    身份证读写器的作用就是从身份证中读取身份信息 xff08 例如姓名 民族 身份证号等 xff09 xff0c 然后显示或者传输给其他模块使用 功能框架如下 xff1a 功能框图说明 xff1a 1 业务模块 负责向安全模块发送命令 xff0
  • JLINK V10 V11固件修复

    先去我的资源里面下载bootloader和app固件文件 步骤 xff1a 1 PC上安装JLINK V4 9工具 xff08 貌似不能使用太高版本的工具 xff0c 否则有问题 xff09 2 打开j flash v4 9 xff0c 新
  • ROS | 话题通信的编程实现

    ROS 话题通信的编程实现 1 创建功能包2 节点编程与消息定义2 1 案例说明2 2 话题消息的定义2 3 创建 cpp文件2 4 话题发布者编程2 5 话题订阅者编程 3 配置与编译3 1 在CMaKeLists txt中添加编译选项3
  • Cocos2dx 3.0配置环境

    3 15 cocos2dx 3 0rc0 终于放出来了 在这里不得不吐槽一件事 xff0c 3 0版本从Alpha xff0c 到beta xff0c 再到rc xff0c 三个版本竟然都有各自创建项目的方式 xff0c 这样真的不会被人打
  • linux 开机运行应用程序

    把运行应用程序的脚本放在 etc rc local里面 xff0c 如果没有 etc rc local xff0c 需要执行前面的3条指令新建这个文件 注意执行应用最好要在后台执行 xff08 后面加个 amp xff09 xff0c 否则
  • arm linux游戏手柄(joystick)驱动移植

    在arm linux中移植usb joystick驱动 xff0c 参考了如下经验 xff1a Linux系统中使用Xbox360手柄 知 行 博客园 cnblogs com 使用BlueZ连接蓝牙手柄 Dokin丶的博客 CSDN博客 蓝
  • linux ubuntu下网络调试助手(GUI)工具

    mNetAssist这个工具在ubuntu下可以运行 xff0c 是个带界面的tcp调试工具 1 UDP通讯 xff1b 2 可做 TCP客户端 xff1b 3 可做 TCP服务器 xff1b 4 可以 十六进制 传送接收数据 5 可以传送
  • fft的通俗解释

    FFT是离散傅立叶变换的快速算法 xff0c 可以将一个信号变换 到频域 有些信号在时域上是很难看出什么特征的 xff0c 但是如 果变换到频域之后 xff0c 就很容易看出特征了 这就是很多信号 分析采用FFT变换的原因 另外 xff0c
  • linux 字符驱动完整框架(poll,async,waitqueue,nonblock等)

    一个linux内核驱动的完整框架 xff0c 包含了能遇到的大部分内容 xff0c 例如timer poll async waitqueue nonblock等等 xff0c 不过基本上没啥大用 xff0c 就是用来熟悉基础的 xff0c
  • vscode远程调试Linux CUDA程序

    参考了 xff1a CUDA 01 第一个程序 知乎 zhihu com 1 本地安装插件 xff1a remote ssh xff0c Microsoft C C 43 43 与NVIDIA Nsight Visual Studio Co
  • 移植MQTT-C库(附源码)

    Software mqtt org 中mqtt客户端的c库里面有一个叫MQTT C的库 xff0c 就2个实现文件 xff0c 算比较简单的了 xff0c 实现了基本的mqtt客户端功能 xff0c 移植一下试试 我的移植代码放在我的资源里
  • TCP协议的滑动窗口和流量控制算法(转)

    目录 滑动窗口 流量控制 操作系统缓冲区与滑动窗口的关系 窗口关闭 糊涂窗口综合症 拥塞控制 慢启动 拥塞避免算法 拥塞发生 快速恢复 拥塞算法示意图 引入 窗口概念的原因 我们都知道 TCP 是每发送一个数据 xff0c 都要进行一次确认
  • linux应用中的时间处理

    参考下 xff1a Linux下有关时间的函数 xff1a time times clock gettimeofday等 linux time函数 见牛羊的博客 CSDN博客 下面的代码基本涵盖了获取时间和操作计时的一些函数使用 xff1a
  • 从旋转向量到欧拉角的六种计算方法

    利用SolvePNP解出旋转向量 xff0c 旋转向量通过罗德里格斯公式解出旋转矩阵 xff0c 然后通过下面六种公式计算即可 xff0c 欧拉角有十二种 xff0c 六种是相对于自身参考系 xff0c 六种是相对于惯性参考系 xff0c
  • ROS | 服务通信的编程实现

    ROS 服务通信的编程实现 1 创建功能包2 节点编程与服务数据定义2 1 案例说明2 2 服务数据的定义2 3 创建 cpp文件2 4 客户端编程2 5 服务器编程 3 配置与编译3 1 在CMaKeLists txt中添加编译选项3 2
  • HTTP基础验证

    HTTP 内置基础验证 浏览器收到401状态码响应后 xff0c 弹出要求输入信息的对话框 通过验证则显示内容 xff0c 不通过不显示需要验证身份的内容 1 xff1b 手动HTTP基础验证 xff1a header 39 http 1
  • 位域,段域,联合体,结构体操作寄存器

    include lt stdio h gt typedef int Uint16 struct SCICCR BITS bit description Uint16 SCICHAR 3 2 0 Character length contro
  • C++ 网络编程之使用socket + epoll 模拟http 的请求与响应

    为了更好的理解http协议 xff0c 笔者使用了C 43 43 socket模拟了一个http服务器 xff0c 其中的服务器使用了epoll的方式 xff0c 并针对每一个新的连接开启新线程处理 大致分为三个部分 xff0c 具体代码可
  • 【Nova】nova-scheduler过滤称重

    在上一篇 nova scheduler调度过程分析 中 xff0c 对过滤称重的过程一笔带过了 xff0c 这篇着重介绍一下 首先 xff0c 我们声明一下host为主机 xff0c node为节点 xff0c 在OpenStack中一个h