当前位置: 首页 > news >正文

手机制作/关键词优化是怎样收费的

手机制作,关键词优化是怎样收费的,自己网站视频直播怎么做,企业管理系统下载文章目录 前言一、Linux传统跨进程通信原理二、Android Binder跨进程通信原理1、动态内核可加载模块2、内存映射3、Binder IPC 实现原理 三、Android Binder IPC 通信模型1、Client/Server/ServiceManager/驱动Binder与路由器之间的角色关系 2、Binder通信过程3、Binder通信中的…

文章目录

  • 前言
  • 一、Linux传统跨进程通信原理
  • 二、Android Binder跨进程通信原理
    • 1、动态内核可加载模块
    • 2、内存映射
    • 3、Binder IPC 实现原理
  • 三、Android Binder IPC 通信模型
    • 1、Client/Server/ServiceManager/驱动
      • Binder与路由器之间的角色关系
    • 2、Binder通信过程
    • 3、Binder通信中的代理模式
    • 4、Binder 的完整定义
  • 四、Binder机制在Android中的具体实现——实现两个数相加
    • 1、定义Client进程需要调用的接口方法
    • 2、建立IPCService
    • 3、MainActivity中bindService,最后将结果显示在TextView中
  • 五、Binder高频面试题
    • 1、Binder为何能实现一次copy?
    • 为什么会出现物理地址和虚拟地址呢?
    • 2、两个进程间的通信Binder原理

前言

对Binder跨进程通信的原理,予以记录!

参考博客:Binder 原理剖析与使用——西门吹雪

Binder 是一种进程间通信机制,基于开源的 OpenBinder 实现;OpenBinder 起初由 Be Inc. 开发,后由 Plam Inc. 接手。

一、Linux传统跨进程通信原理

Linux传统跨进程通信原理

二、Android Binder跨进程通信原理

Android 系统是基于 Linux 内核的,Linux 已经提供了管道、消息队列、共享内存和 Socket 等 IPC 机制。那为什么 Android 还要提供 Binder 来实现 IPC 呢?主要是基于性能、稳定性和安全性几方面的原因。如下图:
在这里插入图片描述
理解了 Linux IPC 相关概念和通信原理,接下来我们正式介绍下 Binder IPC 的原理

1、动态内核可加载模块

传统的 IPC 机制如管道、Socket 都是内核的一部分,因此通过内核支持来实现进程间通信自然是没问题的。但是 Binder 并不是 Linux 系统内核的一部分,那怎么办呢?这就得益于 Linux 的动态内核可加载模块(Loadable Kernel Module,LKM)的机制;模块是具有独立功能的程序,它可以被单独编译,但是不能独立运行。它在运行时被链接到内核作为内核的一部分运行。这样,Android 系统就可以通过动态添加一个内核模块运行在内核空间,用户进程之间通过这个内核模块作为桥梁来实现通信。

在 Android 系统中,这个运行在内核空间,负责各个用户进程通过 Binder 实现通信的内核模块就叫 Binder 驱动(Binder Dirver)

2、内存映射

Binder IPC 机制中涉及到的内存映射通过 mmap() 来实现,mmap() 是操作系统中一种内存映射的方法。内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。

内存映射能减少数据拷贝次数,实现用户空间和内核空间的高效互动。两个空间各自的修改能直接反映在映射的内存区域,从而被对方空间及时感知。也正因为如此,内存映射能够提供对进程间通信的支持。

3、Binder IPC 实现原理

Binder IPC 正是基于内存映射(mmap)来实现的,但是 mmap() 通常是用在有物理介质的文件系统上的。

比如进程中的用户区域是不能直接和物理设备打交道的,如果想要把磁盘上的数据读取到进程的用户区域,需要两次拷贝(磁盘–>内核空间–>用户空间);通常在这种场景下 mmap() 就能发挥作用,通过在物理介质和用户空间之间建立映射,减少数据的拷贝次数,用内存读写取代I/O读写,提高文件读取效率。

在 Android 系统中,这个运行在内核空间,负责各个用户进程通过 Binder 实现通信的内核模块就叫 Binder驱动(Binder Dirver)。

而 Binder 并不存在物理介质,因此 Binder 驱动使用 mmap() 并不是为了在物理介质和用户空间之间建立映射,而是用来在内核空间创建数据接收的缓存空间。

一次完整的 Binder IPC 通信过程通常是这样:

  • 首先 Binder 驱动在内核空间创建一个数据接收缓存区;
  • 接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系;
  • 发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。如下图:
    在这里插入图片描述
    在这里插入图片描述
    说明1:Client进程、Server进程 & Service Manager 进程之间的交互都必须通过Binder驱动(使用 open 和 ioctl文件操作函数),而非直接交互

三、Android Binder IPC 通信模型

介绍完 Binder IPC 的底层通信原理,接下来我们看看实现层面是如何设计的。

一次完整的进程间通信必然至少包含两个进程,通常我们称通信的双方分别为客户端进程(Client)和服务端进程(Server),由于进程隔离机制的存在,通信双方必然需要借助 Binder 来实现。

1、Client/Server/ServiceManager/驱动

Binder 是基于 C/S 架构的。由一系列的组件组成,包括 Client、Server、ServiceManager、Binder 驱动。

  • Client、Server、Service Manager 运行在用户空间,Binder 驱动运行在内核空间。

  • Service Manager 和 Binder 驱动由系统提供,而 Client、Server 由应用程序来实现。

  • Client、Server 和 ServiceManager 均是通过系统调用 open、mmap 和 ioctl 来访问设备文件 /dev/binder,从而实现与 Binder 驱动的交互来间接的实现跨进程通信。
    在这里插入图片描述

说明2:Binder请求的线程管理

Server进程会创建很多线程来处理Binder请求,Binder模型的线程管理采用Binder驱动的线程池,并由Binder驱动自身进行管理而不是由Server进程来管理的

一个进程的Binder线程数默认最大是16,超过的请求会被阻塞等待空闲的Binder线程。所以,在进程间通信时处理并发问题时,如使用ContentProvider时,它的CRUD(创建、检索、更新和删除)方法只能同时有16个线程同时工作

在这里插入图片描述

说明3: Binder驱动 & Service Manager进程 属于 Android基础架构(即系统已经实现好了);而Client 进程 和 Server 进程 属于Android应用层(需要开发者自己实现)

在这里插入图片描述

Client、Server、ServiceManager、Binder 驱动这几个组件在通信过程中扮演的角色就如同互联网中服务器(Server)、客户端(Client)、DNS域名服务器(ServiceManager)以及路由器(Binder 驱动)之前的关系。

Binder与路由器之间的角色关系

通常我们访问一个网页的步骤是这样的:首先在浏览器输入一个地址,如http://www.google.com 然后按下回车键。但是并没有办法通过域名地址直接找到我们要访问的服务器,因此需要首先访问 DNS 域名服务器,域名服务器中保存了 http://www.google.com 对应的 ip 地址 10.249.23.13,然后通过这个 ip 地址才能访问到 http://www.google.com 对应的服务器。

在这里插入图片描述

Binder 驱动就如同路由器一样,是整个通信的核心;驱动负责进程之间 Binder 通信的建立,Binder 在进程之间的传递,Binder 引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。

ServiceManager 和 DNS 类似,作用是将字符形式的 Binder 名字转化成 Client 中对该 Binder 的引用,使得 Client 能够通过 Binder 的名字获得对 Binder 实体的引用。注册了名字的 Binder 叫实名 Binder,就像网站一样除了有 IP 地址外还有自己的网址。Server 创建了 Binder,并为它起一个字符形式,可读易记的名字,将这个 Binder 实体连同名字一起以数据包的形式通过 Binder 驱动发送给 ServiceManager ,通知 ServiceManager 注册一个名为“张三”的 Binder,它位于某个 Server 中。驱动为这个穿越进程边界的 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用,将名字以及新建的引用打包传给 ServiceManager。ServiceManger 收到数据后从中取出名字和引用填入查找表。

ServierManager 是一个进程,Server 是另一个进程,Server 向 ServiceManager 中注册 Binder 必然涉及到进程间通信。当前实现进程间通信又要用到进程间通信,这就好像蛋可以孵出鸡的前提却是要先找只鸡下蛋!Binder 的实现比较巧妙,就是预先创造一只鸡来下蛋。ServiceManager 和其他进程同样采用 Bidner 通信,ServiceManager 是 Server 端,有自己的 Binder 实体,其他进程都是 Client,需要通过这个 Binder 的引用来实现 Binder 的注册,查询和获取。ServiceManager 提供的 Binder 比较特殊,它没有名字也不需要注册。当一个进程使用 BINDERSETCONTEXT_MGR 命令将自己注册成 ServiceManager 时 Binder 驱动会自动为它创建 Binder 实体(这就是那只预先造好的那只鸡)。其次这个 Binder 实体的引用在所有 Client 中都固定为 0 而无需通过其它手段获得。

也就是说,一个 Server 想要向 ServiceManager 注册自己的 Binder 就必须通过这个 0 号引用和 ServiceManager 的 Binder 通信。类比互联网,0 号引用就好比是域名服务器的地址,你必须预先动态或者手工配置好。要注意的是,这里说的 Client 是相对于 ServiceManager 而言的,一个进程或者应用程序可能是提供服务的 Server,但对于 ServiceManager 来说它仍然是个 Client。

2、Binder通信过程

至此,我们大致能总结出 Binder 通信过程:

  • 首先,一个进程使用 BINDERSETCONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager;
  • Server 通过驱动向 ServiceManager 中注册 Binder(Server 中的 Binder 实体),表明可以对外提供服务。驱动为这个 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用,将名字以及新建的引用打包传给 ServiceManager,ServiceManger 将其填入查找表。
  • Client 通过名字,在 Binder 驱动的帮助下从 ServiceManager 中获取到对 Binder 实体的引用,通过这个引用就能实现和 Server 进程的通信。

我们看到整个通信过程都需要 Binder 驱动的接入。下图能更加直观的展现整个通信过程(为了进一步抽象通信过程以及呈现上的方便,下图我们忽略了 Binder 实体及其引用的概念):
在这里插入图片描述

3、Binder通信中的代理模式

我们已经解释清楚 Client、Server 借助 Binder 驱动完成跨进程通信的实现机制了,但是还有个问题会让我们困惑。A 进程想要 B 进程中某个对象(object)是如何实现的呢?毕竟它们分属不同的进程,A 进程 没法直接使用 B 进程中的 object。

前面我们介绍过跨进程通信的过程都有 Binder 驱动的参与,因此在数据流经 Binder 驱动的时候驱动会对数据做一层转换。

  • 当 A 进程想要获取 B 进程中的 object 时,驱动并不会真的把 object 返回给 A,而是返回了一个跟 object 看起来一模一样的代理对象 objectProxy,这个 objectProxy 具有和 object 一摸一样的方法,但是这些方法并没有 B 进程中 object 对象那些方法的能力,这些方法只需要把请求参数交给驱动即可。对于 A 进程来说和直接调用 object 中的方法是一样的。
  • 当 Binder 驱动接收到 A 进程的消息后,发现这是个 objectProxy 就去查询自己维护的表单,一查发现这是 B 进程 object 的代理对象。于是就会去通知 B 进程调用 object 的方法,并要求 B 进程把返回结果发给自己。当驱动拿到 B 进程的返回结果后就会转发给 A 进程,一次通信就完成了。
    在这里插入图片描述

4、Binder 的完整定义

现在我们可以对 Binder 做个更加全面的定义了:

  • 从进程间通信的角度看,Binder 是一种进程间通信的机制;
  • 从 Server 进程的角度看,Binder 指的是 Server 中的 Binder 实体对象;
  • 从 Client 进程的角度看,Binder 指的是对 Binder 代理对象,是 Binder 实体对象的一个远程代理
  • 从传输过程的角度看,Binder 是一个可以跨进程传输的对象;Binder 驱动会对这个跨越进程边界的对象做一点点特殊处理,自动完成代理对象和本地对象之间的转换。

四、Binder机制在Android中的具体实现——实现两个数相加

1、定义Client进程需要调用的接口方法

public interface IPlus extends IInterface {//定义需要实现的接口方法,即Client进程需要调用的方法public int add(int a, int b);
}

2、建立IPCService

public class IPCService extends Service {public static final String DESCRIPTOR = "add two int";private final MyAddBinder mBinder = new MyAddBinder();public IPCService() {/*** 将(descriptor, plus)作为(key, value)对存入到Binder对象中的一个Map<String, IInterface>中* 之后binder对象可根据descriptor找到对应IInterface对象的引用,进而调用其方法** @param plus* @param descriptor*/IPlus plus = new IPlus() {@Overridepublic int add(int a, int b) {return a + b;}@Overridepublic IBinder asBinder() {return null;}};/*** 1.将(add two int,plus)作为(key,value)对存入到Binder对象中的一个Map<String,IInterface>对象中* 2.之后,Binder对象可根据add two int通过queryLocalIInterface()获得对应IInterface对象*/mBinder.attachInterface(plus, DESCRIPTOR);}private class MyAddBinder extends Binder {/*** 继承自IBinder接口的,执行Client进程所请求的目标的方法(子类需要复写该方法)* 注:运行在Server进程的Binder线程池中;当Client进程发起远程请求时,远程请求会要求系统底层执行回调该方法* @param code Client进程请求方法标识符。即Server进程根据该标识确定所请求的目标方法* @param data 目标方法的参数。(Client进程传进来的,此处就是整数a和b)* @param reply 目标方法执行后的结果(返回给Client进程)* @param flags* @return*/@Overrideprotected boolean onTransact(int code, @NonNull Parcel data, Parcel reply, int flags)throws RemoteException {if (code == 1) {Log.d("TAG", "MyBinder Switch块 -----" + Process.myPid());data.enforceInterface(DESCRIPTOR);int a = data.readInt();int b = data.readInt();int result = ((IPlus) this.queryLocalInterface(DESCRIPTOR)).add(a, b);reply.writeNoException();reply.writeInt(result);return true;}Log.d("TAG", "MyBinder   OnTransact() ----- " + android.os.Process.myPid());return super.onTransact(code, data, reply, flags);}}@Nullable@Overridepublic IBinder onBind(Intent intent) {return mBinder;}
}

3、MainActivity中bindService,最后将结果显示在TextView中

public class MainActivity extends AppCompatActivity implements View.OnClickListener {public static final String DESCRIPTOR1 = "add two int";private EditText editText1;private EditText editText2;private TextView resultText;private Button addBtn;private Button subtractBtn;private IBinder mBinder;private final ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mBinder = service;Log.d("TAG", "客户端-----" + android.os.Process.myPid());}@Overridepublic void onServiceDisconnected(ComponentName name) {mBinder = null;}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bindViews();addBtn.setOnClickListener(this);subtractBtn.setOnClickListener(this);//service方式Intent service = new Intent(this, IPCService.class);bindService(service, mServiceConnection, BIND_AUTO_CREATE);}private void bindViews() {editText1 = (EditText) findViewById(R.id.edit_arg1);editText2 = (EditText) findViewById(R.id.edit_arg2);resultText = (TextView) findViewById(R.id.result_arg);addBtn = (Button) findViewById(R.id.btn_add);subtractBtn = (Button) findViewById(R.id.btn_subtract);}@Overridepublic void onClick(View v) {int id = v.getId();if (id == R.id.btn_add) {add();}}public void add() {int a = Integer.parseInt(editText1.getText().toString());int b = Integer.parseInt(editText2.getText().toString());if (mBinder != null) {Parcel _data = Parcel.obtain();Parcel _reply = Parcel.obtain();int _result = -1;try {_data.writeInterfaceToken(DESCRIPTOR1);_data.writeInt(a);_data.writeInt(b);mBinder.transact(1, _data, _reply, 0);_reply.readException();_result = _reply.readInt();resultText.setText(_result + "");Toast.makeText(MainActivity.this, "result:" + _result,Toast.LENGTH_SHORT).show();} catch (RemoteException e) {throw new RuntimeException(e);} finally {_reply.recycle();_data.recycle();}} else {Toast.makeText(MainActivity.this, "未连接服务端或服务端异常!",Toast.LENGTH_SHORT).show();}}
}

在这里插入图片描述

五、Binder高频面试题

1、Binder为何能实现一次copy?

Binder的一次copy是利用了mmap(内存映射文件:目的是开辟物理地址),内存映射文件是在堆和栈的空余空间
mmap是在linux中的api,可以通过mmap去开辟物理地址空间。
MMU(Memeory Mananger Unit)将mmap开辟的物理内存地址转化成虚拟内存地址

物理地址:内存条上的地址;
虚拟地址:实际上是MMU提供的虚拟地址;

Binder采用的是C/S模式的,其中提供服务的进程成为Server进程,访问服务的进程成为Client进程;Server和Client进程通信要依靠运行在内核空间的Binder驱动程序来进行;

Service组件在开启时,会将自己注册到一个Service Manager里,以便于Client进程在ServiceManager中找到它;因此ServiceManager也称为Binder进程间通信的上下文管理者;同时它也需要和普通的Server进程和Client进程通信,所以也是可以看做一个特殊的Service组件;

注:Binder通信机制中的Service组件和Android中的Service组件是不同的概念;Service Manager里注册服务是在进程间的注册

为什么会出现物理地址和虚拟地址呢?

由于现在的程序app大小都很大了,如果全部加载到内存中去运行需要很多内存,而手机的内存是有限的,又由于当你在运行一个app的时候不是所有的代码都会被加载到内存中去运行,只会加载一部分正在活动的代码,为了满足程序局部性原则,这时出现的物理地址和虚拟地址刚好能解决,能省下不用的内存空间供其他app使用

物理地址:内存条上的地址;
虚拟地址:MMU提供的虚拟的地址;

MMU(Memory Management Unit)内存管理单元:涉及到一个转换物理地址和虚拟地址;
为什么会存在MMU,因为app的整体大小假如是100M,但是实际的活跃代码在内存中只有1M,其他的代码处于磁盘中,所以,cpu在运行代码的时候不可能说只给1M的内存让cpu在里面运行,所以需要给一个MMU中间件,让CPU感觉运行在512M的内存中。

MMU里有页表:页表里保存有效位+地址,有效位为0表示未缓存,为1表示已缓存,只要有效位是1就肯定有地址;

虚拟地址和物理地址,如果虚拟地址中没有的话,MMU就会读取磁盘并拿出来在内存中开辟一块新的空间,并在MMU中存放物理地址和对应的虚拟地址,cpu就会拿到虚拟地址;

2、两个进程间的通信Binder原理

Binder的通信是进程A调用copy_form_user,到内核空间,内核空间同进程B建立了链接,copy_to_user会将数据传给B进程;而进程间的通信大小是1M-8K(copy到内核空间),8K是由于有请求头等信息,一页是4K,需要是4的整数倍;

页:cpu为了高效执行以及内存管理,每次需要拿一个页的代码,这个页表示一块连续的储存空间。常见的4kb,也称为块。

假如页的大小为P,那么在虚拟内存中VP就称为虚拟页;从虚拟内存中拿到的一页的代码放在物理内存中,那么物理内存中也得有一个同样大小可以页存放虚拟页的代码,物理内存中的页称为物理页(PP);

在任何时刻,虚拟页都有以下三种状态中的一种,且以下状态都是在MMU中体现:

未分配的:VM还未分配页(或者未创建),未分配的页还没有任何数据与代码与他们关联,因此也就不占任何磁盘;已缓存的:当前缓存在物理内存中已分配页;未缓存的:当前未缓存在屋里内存中已分配页;

相关文章:

Android Framework通信:Binder

文章目录 前言一、Linux传统跨进程通信原理二、Android Binder跨进程通信原理1、动态内核可加载模块2、内存映射3、Binder IPC 实现原理 三、Android Binder IPC 通信模型1、Client/Server/ServiceManager/驱动Binder与路由器之间的角色关系 2、Binder通信过程3、Binder通信中的…...

如何用精准测试来搞垮团队?

测试行业每年会冒出来一些新鲜词&#xff1a;混沌工程、精准测试、AI测试…… 这些新概念、新技术让我们感到很焦虑&#xff0c;逼着自己去学习和了解这些新玩意&#xff0c;担心哪一天被淘汰掉。 以至于给我这样的错觉&#xff0c;当「回归测试」、「精准测试」这两个词摆在一…...

暴力递归转动态规划(十)

题目 给定一个二维数组matrix[][]&#xff0c;一个人必须从左上角出发&#xff0c;最终到达右下角&#xff0c;沿途只可以向下或者向右走&#xff0c;沿途的数字都累加就是距离累加和。返回最小距离累加和。 这道题中会采用压缩数组的算法来进行优化 暴力递归 暴力递归方法的整…...

深度学习-房价预测案例

1. 实现几个函数方便下载数据 import hashlib import os import tarfile import zipfile import requests#save DATA_HUB dict() DATA_URL http://d2l-data.s3-accelerate.amazonaws.com/def download(name, cache_diros.path.join(.., data)): #save"""下载…...

【26】c++设计模式——>命令模式

c命令模式 C的命令模式是一种行为模式&#xff0c;通过将请求封装成对象&#xff0c;以实现请求发送者和接受者的解耦。 在命令模式中&#xff0c;命令被封装成一个包含特定操作的对象&#xff0c;这个对象包含的执行该操作的方法&#xff0c;以及一些必要的参数。命令对象可以…...

ElasticSearch容器化从0到1实践(一)

背景 通过kubernetes集群聚合多个Elasticsearch集群碎片资源&#xff0c;提高运维效率。 介绍 Kubernetes Operator 是一种特定的应用控制器&#xff0c;通过 CRD&#xff08;Custom Resource Definitions&#xff0c;自定义资源定义&#xff09;扩展 Kubernetes API 的功能…...

【Vue面试题二十四】、Vue项目中有封装过axios吗?主要是封装哪方面的?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;Vue项目中有封装过axios…...

旅游票务商城小程序的作用是什么

随着环境放开&#xff0c;旅游行业恢复了以往的规模&#xff0c;本地游、外地游成为众多用户选择&#xff0c;而在旅游时&#xff0c;不少人会报名旅行团前往各风景热点游玩&#xff0c;对旅游票务经营者而言&#xff0c;市场高需求的同时也面临一些难题。 对旅游票务经营商家…...

LabVIEW在安装了其它的NI软件之后崩溃了

LabVIEW在安装了其它的NI软件之后崩溃了 在安装了其它的NI软件之后&#xff0c;一些原本安装好的或者新安装的软件由于缺少必要的DLL而崩溃掉了。例如&#xff0c;在这种情况下&#xff0c;Teststand可能会报下面的错误&#xff1a; RetrievingCOM class factory for compone…...

基于Java的个人健康管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...

nginx https的配置方法

文章目录 安装证书工具安装根证书生成域名证书配置转发 ssl的请求到http请求 安装证书工具 curl ‘http://pan.itshine.cn:5080/?explorer/share/fileOut&shareID64h6PiQQ&path%7BshareItemLink%3A64h6PiQQ%7D%2F%E5%B7%A5%E5%85%B7%2Fmkcert’ > ‘./mkcert’ c…...

使用WebDriver采样器将JMeter与Selenium集成

目录 第一步&#xff1a;在JMeter中添加Selenium / WebDriver插件 第二步&#xff1a;创建一条测试计划--添加线程组 第三步&#xff1a;下载 chromedriver.exe 第四步&#xff1a;在Web Driver 采样器中添加测试脚本 第五步&#xff1a;运行并且验证 注意&#xff1a; 第…...

flink教程

文章目录 来自于尚硅谷教程1. Flink概述1.1 特点1.2 与SparkStreaming对比 2. Flink部署2.1 集群角色2.2 部署模式2.3 Standalone运行模式2.3.1 本地会话模式部署2.3.2 应用模式 2.4 YARN运行模式2.4.1 会话模式部署2.4.2 应用模式部署 2.5 历史服务 3. 系统架构3.1 并行度3.2 …...

视频监控系统/安防视频平台EasyCVR广场视频细节优化

安防视频监控系统/视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。安防视频汇聚平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;可实现视频监控直播、视频轮播、…...

电脑上播放4K视频需要具备哪些条件?

在电视上播放 4K&#xff08; 4096 2160 像素&#xff09;视频是很简单的&#xff0c;但在电脑设备上播放 4K 视频并不容易。相反&#xff0c;它们有自己必须满足的硬件要求。 如果不满足要求&#xff0c;在电脑上打开 4K 分辨率文件或大型视频文件会导致卡顿、音频滞后以及更…...

测试除了点点点,还有哪些内容呢?

今天和一个网友讨论了一下关于互联网行业中测试的情况&#xff0c;希望能够了解现在的互联网行业主要的测试工作内容。小编根据以往的工作经历和经验情况&#xff0c;来做一个总结和整理。 1、岗位分类 现在的岗位划分主要是分为两大类&#xff1a;测试工程师 和 测试开发工程…...

HTTP的本质理解

HTTP是超文本传输协议&#xff0c;从协议、传输和超文本三个关键词进行进行分解。 协议关键词讲解 1.协议的第一个词是协&#xff0c;这个就表明需要至少两方参与到其中。 2.协议的第二个词是议&#xff0c;表明HTTP是规范和约定&#xff0c;需要大家共同遵守&#xff0c;也包…...

微信小程序获取公众号的文章

背景&#xff1a;我有一个《砂舞指南》的小程序&#xff0c;主要是分享砂舞最新动态等 最近做了一个小程序&#xff0c;想要一些固定的文章展示在小程序里面&#xff0c;比如《什么是砂舞》《玩砂舞注意点》等普及砂舞知识的文章 开发流程&#xff1a; 1、刚开始测试了 素材…...

【算法|动态规划No.20】leetcode416. 分割等和子集

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…...

深入解析C语言中的strstr函数

目录 一&#xff0c;strstr函数简介 二&#xff0c;strstr函数实现原理 三&#xff0c;strstr函数的用法 四&#xff0c;strstr函数的注意事项 五&#xff0c;strstr函数的模拟实现 一&#xff0c;strstr函数简介 strstr函数是在一个字符串中查找另一个字符串的第一次出现&…...

HDLbits: Fsm serial

根据题意设计了四个状态&#xff0c;写出代码如下&#xff1a; module top_module(input clk,input in,input reset, // Synchronous resetoutput done ); parameter IDLE 3b000, START 3b001, DATA 3b010, STOP 3b100, bit_counter_end 4d7;reg [2:0] state,next_sta…...

LuaJit交叉编译移植到ARM Linux

简述 Lua与LuaJit的主要区别在于LuaJIT是基于JIT&#xff08;Just-In-Time&#xff09;技术开发的&#xff0c;可以实现动态编译和执行代码&#xff0c;从而提高了程序的运行效率。而Lua是基于解释器技术开发的&#xff0c;不能像LuaJIT那样进行代码的即时编译和执行。因此&…...

【RocketMQ系列一】初识RocketMQ

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…...

【06】基础知识:React组件实例三大核心属性 - ref

一、 ref 了解 理解 组件内的标签可以定义 ref 属性来标识自己 使用 1、字符串形式的 ref 定义&#xff1a;<input ref"input"/> 获取&#xff1a;this.refs.input2、回调形式的 ref 定义&#xff1a;<input ref{currentNode > this.input curren…...

Bootstrap-媒体类型

加上媒体查询之后&#xff0c;只有在特定的设备之下才能起作用&#xff01;&#xff01;&#xff01;...

spring Cloud笔记--服务治理Eureka

服务治理&#xff1a;Eureka 服务治理 主要用来实现各个微服务实例的自动化注册与发现 服务注册&#xff1a; 服务治理框架中&#xff0c;通常会构建一个注册中心&#xff0c;每个服务单元向注册中心登记自己提供的服务&#xff0c;将主机与端口号&#xff0c;版本号&#x…...

pdf压缩文件怎么压缩最小?pdf压缩方法汇总

PDF是一种常见的文件格式&#xff0c;通常用于电子文档和印刷品&#xff0c;由于PDF文件通常包含大量的元数据、字体、图像和其他元素&#xff0c;因此它们的大小可能会非常大。 为了解决这个问题&#xff0c;我们可以使用一些PDF压缩工具来帮助我们&#xff0c;以便我们能够更…...

Golang学习记录:基础篇练习(一)

Golang学习记录&#xff1a;基础篇练习&#xff08;一&#xff09; 1、九九乘法表2、水仙花数3、斐波那契数列4、编写一个函数&#xff0c;求100以内的质数5、统计字符串里面的字母、数字、空格以及其他字符的个数6、二维数组对角线的和7、冒泡排序算法8、选择排序算法9、二分查…...

sql注入(7), python 实现盲注爆破数据库名, 表名, 列名

python 实现盲注 该python脚本根据之前介绍的盲注原理实现, 对于发送的注入请求没有做等待间隔, 可能给目标服务器造成一定 压力, 所以仅限于本地测试使用. import requests, time# 时间型盲注 def time_blind(base_url, cookie):for length in range(1, 20): # 测试数据库名…...

2021年12月 Python(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python编程&#xff08;1~6级&#xff09;全部真题・点这里 C/C编程&#xff08;1~8级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 执行以下程序 a[33,55,22,77] a.sort() for i in a:print(i)运行…...