编写云计算计费系统
admin
2024-03-19 09:43:57
0

上一篇介绍了自建一个Laxcus云服务需要了解的基础知识,这一篇咱们从编程角度,来说说如何编写一个简单的云服务计费系统,如果你有更复杂的需求,可以在这个上面扩展。更进一步,如果你非常熟悉Laxcus分布式操作系统的运行流程,那么可以去GitHub拿源代码修改,甚至直接操作底层或者硬件获取必要信息,这样会更贴近你的需求。
闲话不多说,咱们正式进入主题。
编写一个简单的Laxcus云服务计费系统,需要这样三步:
1.了解Check User Cost命令。
2.了解Check User Cost命令的返回结果。
3.生成Check User Cost命令,调用系统DSDK软件包的API,把命令投递到Laxcus计算机集群上执行,然后等待返回结果,解析结果中的信息,结合你的计费算法,得出计费结果。

目前Laxcus分布式操作系统的DSDK软件包,只支持Java编程,同类型的C、C++接口、Python接口,还处于Alpha状态,暂时没有公布出来。所以咱们这篇文章就以Java编程的方式,来介绍编写Laxcus云服务计费的系统。

一、Check User Cost命令
Check User Cost命令的源代码如下

public class CheckUserCostProduct extends EchoProduct {private static final long serialVersionUID = 3146106632408001248L;/** 用户签名 -> 单元 **/private Map array = new TreeMap();/*** 构造默认的服务器系统信息检测结果*/public CheckUserCostProduct() {super();}/*** 从可类化数据读取器解析服务器系统信息检测结果* @param reader 可类化数据读取器*/public CheckUserCostProduct(ClassReader reader) {this();resolve(reader);}/*** 构造服务器系统信息检测结果的数据副本* @param that CheckUserCostProduct实例*/private CheckUserCostProduct(CheckUserCostProduct that) {super(that);array.putAll(that.array);}/*** 加一个* @param product*/public void add(CheckUserCostProduct product) {for (UserCostElement element : product.array.values()) {add(element.getIssuer(), element);}}/*** 加全部* @param issuer 用户签名* @param element 成员*/public void add(Siger issuer, UserCostElement element) {UserCostElement that = array.get(issuer);if (that != null) {that.addAll(element.list());} else {array.put(issuer, element);}}/*** 加一个单元* @param issuer 签名* @param item 成员*/public void add(Siger issuer, UserCostItem item) {UserCostElement element = array.get(issuer);if (element != null) {element.add(item);} else {element = new UserCostElement(issuer);element.add(item);array.put(element.getIssuer(), element);}}/*** 输出全部* @return*/public List list() {return new ArrayList(array.values());}/*** 查找一个成员* @param siger 签名* @return 返回匹配的成员*/public UserCostElement find(Siger siger) {return array.get(siger);}/*** 判断是空* @return*/public boolean isEmpty() {return array.isEmpty();}/*** 有效单元数目* @return 整数*/public int size() {return array.size();}/* (non-Javadoc)* @see com.laxcus.echo.product.EchoProduct#duplicate()*/@Overridepublic CheckUserCostProduct duplicate() {return new CheckUserCostProduct(this);}/* (non-Javadoc)* @see com.laxcus.echo.product.EchoProduct#buildSuffix(com.laxcus.util.ClassWriter)*/@Overrideprotected void buildSuffix(ClassWriter writer) {writer.writeInt(array.size());for (UserCostElement e : array.values()) {writer.writeObject(e);}}/* (non-Javadoc)* @see com.laxcus.echo.product.EchoProduct#resolveSuffix(com.laxcus.util.ClassReader)*/@Overrideprotected void resolveSuffix(ClassReader reader) {int size = reader.readInt();for (int i = 0; i < size; i++) {UserCostElement element = new UserCostElement(reader);add(element.getIssuer(), element);}}}

Check User Cost类中的变量需要做点解释
1. 节点类型,它的定义,可以查阅SiteTag类的源代码,目前是除Front节点和Watch节点之外,都能够支持,Front节点和Watch注册用户和系统管理员使用的节点,并不涉及计费问题。如果指定全部节点,那么all变量设成“true”。
2. 用户签名,对应Siger类,它的本质就是一个SHA256签名。生成SHA256签名可以使用Laxkit类的doSiger方法来实现,doSiger方法的作用是把一个字符串转换成数字签名,输入是字符文本,输出是Siger类。
3. 查询的命名。在Laxcus集群里,所有分布式计算工作都有一个名称,比如执行大型的分布式计算工作,对应CONDUCT名称,如果上传文件到云端,对应UPLOAD CLOUD FILE名称。依此类推。Naming的作用是忽略大小写,即一个 CONDUCT和conduct等价。如果置空,表示搜索与用户签名相关的全部命令
4. 忽略的命令。它的作用和查询命名相反,即不查询某些命名。
5. 开始、结束命令。这个参数是一个长整数值,使用转义函数来取得。

比如我们想查询2022年12月1日到2022年12月2日两天,一个名为“Tubex“的用户记录,但是不包括CONDUCT命名,那么生成CheckUserCost的命令可以这样写:

CheckUserCost cmd = new CheckUserCost();
cmd.setAll(true);
Siger siger = Laxkit.doSiger(“tubex”);
cmd.addUser(siger);
cmd.addExclude(new Naming("conduct"));
long timestamp = CalendarGenerator.splitTimestamp("2022-12-1");
cmd.setBeginTime(timestamp);
timestamp = CalendarGenerator.splitTimestamp("2022-12-2");
cmd.setEndTime(timestamp);

二、Check User Cost命令的返回结果
Check User Cost命令的返回结果对应CheckUserCostProduct类,CheckUserCostProduct继承自EchoProduct,保存所有检索结果。参数是基于用户签名和查询单元的TreeMap,CheckUserCostProduct类中包含了UserCostElement类,而UserCostElement类又包含UserCostItem类,这样就形成了“CheckUserCostProduct -> CheckUserCostElement -> UserCostItem”三级关系。因为CheckUserCostProduct类和UserCostElement类比较简单,咱们重点说说UserCostItem类。如果开发者想增加更多的计费元素,可以结合需求调用系统底层修改UserCostItem的源代码。

UserCostItem源代码如下:

public final class UserCostItem implements Classable, Cloneable, Serializable, Comparable {private static final long serialVersionUID = -6293384810197643693L;/** 节点类型 **/private byte family;/** 调用器编号 **/private long invokerId;/** 迭代次数 **/private int iterateIndex;/** 操作命名 **/private String command;/** 开始和结束时间 **/private long initTime, endTime;/** 被线程调用,在EchoInvoker中的迭代时间 **/private long threadIterateTime;/** 接收数据流量 **/private long receiveFlows;/** 发送数据流量 **/private long sendFlows;/** 服务号,对应Command的slogan,全局唯一 **/private long slogan;/** 服务迭代编号,对应服务号,根据分布流程,从1开始逐次传递增加 **/private int sloganIndex;/** 命令级别,对应Command类 **/private byte priority;/*** 构造默认的被刷新处理单元*/public UserCostItem() {super();family = 0;invokerId = 0;iterateIndex = 0;command = null;initTime = 0;endTime = 0;threadIterateTime = 0;receiveFlows = 0;sendFlows = 0;slogan = 0;sloganIndex = 0;priority = 0;}/*** 根据传入实例,生成用户消费单元的数据副本* @param that UserCostItem实例*/private UserCostItem(UserCostItem that) {super();family = that.family;invokerId = that.invokerId;iterateIndex = that.iterateIndex;command = that.command;initTime = that.initTime;endTime = that.endTime;threadIterateTime = that.threadIterateTime;receiveFlows = that.receiveFlows;sendFlows = that.sendFlows;slogan = that.slogan;sloganIndex = that.sloganIndex;priority = that.priority;}/*** 从可类化数据读取器中用户消费单元* @param reader 可类化数据读取器*/public UserCostItem(ClassReader reader) {this();resolve(reader);}/*** 设置节点类型* @param who*/public void setFamily(byte who) {family = who;}/*** 返回节点类型* @return*/public byte getFamily() {return family;}/*** 设置调用器编号* @param id 编号*/public void setInvokerId(long id) {invokerId = id;}/*** 返回调用器编号* @return 毫秒*/public long getInvokerId() {return invokerId;}/*** 设置迭代次数* @param i*/public void setIterateIndex(int i) {iterateIndex = i;}/*** 返回迭代次数* @return*/public int getIterateIndex() {return iterateIndex;}/*** 设置命令* @param s*/public void setCommand(String s) {command = s;}/*** 返回命令* @return*/public String getCommand() {return command;}/*** 设置初始时间* @param ms*/public void setInitTime(long ms) {initTime = ms;}/*** 返回初始时间* @return*/public long getInitTime() {return initTime;}/*** 设置结束时间* @param ms*/public void setEndTime(long ms) {endTime = ms;}/*** 返回结束时间* @return*/public long getEndTime() {return endTime;}/*** 设置被线程调用,在EchoInvoker中的迭代时间* @param ms 毫秒*/public void setThreadIterateTime(long ms) {threadIterateTime = ms;}/*** 返回被线程调用,在EchoInvoker中的迭代时间* @return 毫秒*/public long getThreadIterateTime() {return threadIterateTime;}/*** 设置接收数据流尺寸* @param len 数据长度*/public void setReceiveFlows(long len) {receiveFlows = len;}/*** 返回接收数据流尺寸* @return 数据长度*/public long getReceiveFlows() {return receiveFlows;}/*** 设置发送数据流尺寸* @param len 数据长度*/public void setSendFlows(long len) {sendFlows = len;}/*** 返回发送数据流尺寸* @return 数据长度*/public long getSendFlows() {return sendFlows;}/*** 设置服务号* @param no 服务号*/public void setSlogan(long no) {slogan = no;}/*** 返回服务号* @return 服务号*/public long getSlogan() {return slogan;}/*** 设置服务编号,不定义是0* @param no 长整型*/public void setSloganIndex(int no) {sloganIndex = no;}/*** 返回服务编号* @return 长整型*/public int getSloganIndex() {return sloganIndex;}/*** 设置命令优先级* @param no 命令优先级*/public void setPriority(byte no) {priority = no;}/*** 返回命令优先级* @return 命令优先级*/public byte getPriority() {return priority;}/*** 生成当前实例的数据副本* @return UserCostItem实例*/public UserCostItem duplicate() {return new UserCostItem(this);}/** (non-Javadoc)* @see java.lang.Object#clone()*/@Overridepublic Object clone() {return duplicate();}/** (non-Javadoc)* @see java.lang.Object#hashCode()*/@Overridepublic int hashCode() {return (int) ((invokerId >>> 32) ^ invokerId);}/** (non-Javadoc)* @see java.lang.Object#equals(java.lang.Object)*/@Overridepublic boolean equals(Object that) {if (that == null || getClass() != that.getClass()) {return false;} else if (that == this) {return true;}// 比较return compareTo((UserCostItem ) that) == 0;}/* (non-Javadoc)* @see java.lang.Comparable#compareTo(java.lang.Object)*/@Overridepublic int compareTo(UserCostItem that) {int ret = Laxkit.compareTo(family, that.family);if (ret == 0) {ret = Laxkit.compareTo(initTime, that.initTime);}if (ret == 0) {ret = Laxkit.compareTo(command, that.command, false);}if (ret == 0) {ret = Laxkit.compareTo(invokerId, that.invokerId);}return ret;}/* (non-Javadoc)* @see com.laxcus.util.Classable#build(com.laxcus.util.ClassWriter)*/@Overridepublic int build(ClassWriter writer) {int size = writer.size();buildSuffix(writer);return writer.size() - size;}/* (non-Javadoc)* @see com.laxcus.util.Classable#resolve(com.laxcus.util.ClassReader)*/@Overridepublic int resolve(ClassReader reader) {int seek = reader.getSeek();resolveSuffix(reader);return reader.getSeek() - seek;}/*** 保存参数* @param writer */protected void buildSuffix(ClassWriter writer) {writer.write(family);writer.writeLong(invokerId);writer.writeInt(iterateIndex);writer.writeString(command);writer.writeLong(initTime);writer.writeLong(endTime);writer.writeLong(threadIterateTime);writer.writeLong(receiveFlows);writer.writeLong(sendFlows);writer.writeLong(slogan);writer.writeInt(sloganIndex);writer.write(priority);}/*** 解析参数* @param reader*/protected void resolveSuffix(ClassReader reader) {family = reader.read();invokerId = reader.readLong();iterateIndex = reader.readInt();command = reader.readString();initTime = reader.readLong();endTime = reader.readLong();threadIterateTime = reader.readLong();receiveFlows = reader.readLong();sendFlows = reader.readLong();slogan = reader.readLong();sloganIndex = reader.readInt();priority = reader.read();}}

下面说说UserCostItem比较重要的一些参数,通过这些参数,结束计费算法规则,你将最终得到你的计费
1. family,节点类型,它对应SiteTag中的节点类型
2. invokerId,调用器编号,也可以理解为进程编号。如果查阅系统日志,把它和节点类型结合,可以定位提取出调用器产生的运行记录。
3. iterateIndex,迭代次数。Laxcus调用器存在被系统多次调用的可能,迭代编号是指它循环执行的次数。多次迭代之间,调用器会被系统悬挂起来,直到运行条件满足再次触发执行。迭代次数理论上最少1次,最多不限。
4. command,操作命名,这个参数对应CheckUserCost中的includes参数。
5. initTime, endTime,调用器的第一次启动时间和最后时间,两个参数的差值,就是调用器运行的总时间。如果以时间为标准进行计费,通过这个时间,结合计费结合,可以得出一个计费结果。
6. receiveFlows,调用器在分布计算过程中,接收得到的数据流量。流量以字节为单位,这个参数通常是各种计费标准的主要依据之一。
7. sendFlows,调用器在分布计算过程中,发送出去的数据流量。这个参数同样也是计费标准参照之一。
8. slogan,服务号,是一个64位的整数值。它在分布计算执行前由系统赋值,保证运行环境全局唯一,如果分布计算过程中产生了分裂(类似Linux编程中的fork),这个服务号也会被继承下来。通过服务号,无论分布计算在多少个节点执行,其间发生了多少次分裂,都可以把它们记录下来,然后反向推导出分布计算执行的先后顺序和分布执行情况。如果有需要,在这个基础上,进一步形成可视化的分布计算执行流程图表,必要时提供给用户,做为分布计算的佐证之一。
9. sloganIndex,服务迭代编号,即关联服务号的调用器,在分布式计算过程中发生了分裂,就在这个编号上做一个加1的操作。服务迭代编号从1开始,随着调用器分裂逐层传递增加。
10. priority,操作执行优先级,前一篇说过,用户的分布业务,有四个级别,从大到小分为MAX级,NORMAL级,MINI级,NONE级。调整用户优先级由管理员来操作,默认情况下,所有用户都是NONE级,即不定义优先级。获得更高优先级应用业务,总是比低于它一级的应用业务,优先取得Laxcus计算机集群的资源,优先取得执行权限进行分布计算工作。所以priority也是一个计费参照之一,更高优先级的业务,在享受优先处理权利时,也应该付出更多的消费金额。

下面是UserCostElement类和CheckUserCostProduct类的源程序代码,因为比较简单,就不单独说明了。

public final class UserCostElement implements Classable, Cloneable, Serializable, Comparable {private static final long serialVersionUID = 5651643178030182283L;/** 用户签名 **/private Siger issuer;/** 未使用容量 **/private TreeSet array = new TreeSet();/*** 构造默认的用户资源消耗成员*/public UserCostElement() {super();}/*** 构造用户资源消耗成员* @param issuer 用户签名*/public UserCostElement(Siger issuer) {this();setIssuer(issuer);}/*** 根据传入实例,生成用户资源消耗成员的数据副本* @param that UserCostElement实例*/private UserCostElement(UserCostElement that) {super();issuer = that.issuer;array.addAll(that.array);}/*** 从可类化数据读取器中用户资源消耗成员* @param reader 可类化数据读取器*/public UserCostElement(ClassReader reader) {this();resolve(reader);}/*** 设置用户签名* @param who 签名*/public void setIssuer(Siger who) {issuer = who;}/*** 返回用户签名* @return 签名*/public Siger getIssuer() {return issuer;}/*** 加一个单元* @param item* @return*/public boolean add(UserCostItem item) {if (item != null) {return array.add(item);}return false;}/*** 增加一批单元* @param a* @return*/public int addAll(Collection a) {int size = array.size();if (a != null) {for (UserCostItem item : a) {add(item);}}return array.size() - size;}/*** 返回单元* @return*/public List list() {return new ArrayList(array);}/*** 全部成员* @return*/public int size() {return array.size();}/*** 生成当前实例的数据副本* @return UserCostElement实例*/public UserCostElement duplicate() {return new UserCostElement(this);}/** (non-Javadoc)* @see java.lang.Object#clone()*/@Overridepublic Object clone() {return duplicate();}/** (non-Javadoc)* @see java.lang.Object#equals(java.lang.Object)*/@Overridepublic boolean equals(Object that) {if (that == null || getClass() != that.getClass()) {return false;} else if (that == this) {return true;}// 比较return compareTo((UserCostElement) that) == 0;}/* (non-Javadoc)* @see java.lang.Comparable#compareTo(java.lang.Object)*/@Overridepublic int compareTo(UserCostElement that) {if (that == null) {return 1;}// 比较参数return Laxkit.compareTo(issuer, that.issuer);}/* (non-Javadoc)* @see com.laxcus.util.Classable#build(com.laxcus.util.ClassWriter)*/@Overridepublic int build(ClassWriter writer) {int size = writer.size();buildSuffix(writer);return writer.size() - size;}/* (non-Javadoc)* @see com.laxcus.util.Classable#resolve(com.laxcus.util.ClassReader)*/@Overridepublic int resolve(ClassReader reader) {int seek = reader.getSeek();resolveSuffix(reader);return reader.getSeek() - seek;}/*** 保存参数* @param writer */protected void buildSuffix(ClassWriter writer) {writer.writeObject(issuer);int size = array.size();writer.writeInt(size);for (UserCostItem e : array) {writer.writeObject(e);}}/*** 解析参数* @param reader*/protected void resolveSuffix(ClassReader reader) {issuer = new Siger(reader);int size = reader.readInt();for (int i = 0; i < size; i++) {UserCostItem item = new UserCostItem(reader);add(item);}}}
public class CheckUserCostProduct extends EchoProduct {private static final long serialVersionUID = 3146106632408001248L;/** 用户签名 -> 单元 **/private Map array = new TreeMap();/*** 构造默认的服务器系统信息检测结果*/public CheckUserCostProduct() {super();}/*** 从可类化数据读取器解析服务器系统信息检测结果* @param reader 可类化数据读取器*/public CheckUserCostProduct(ClassReader reader) {this();resolve(reader);}/*** 构造服务器系统信息检测结果的数据副本* @param that CheckUserCostProduct实例*/private CheckUserCostProduct(CheckUserCostProduct that) {super(that);array.putAll(that.array);}/*** 加一个* @param product*/public void add(CheckUserCostProduct product) {for (UserCostElement element : product.array.values()) {add(element.getIssuer(), element);}}/*** 加全部* @param issuer 用户签名* @param element 成员*/public void add(Siger issuer, UserCostElement element) {UserCostElement that = array.get(issuer);if (that != null) {that.addAll(element.list());} else {array.put(issuer, element);}}/*** 加一个单元* @param issuer 签名* @param item 成员*/public void add(Siger issuer, UserCostItem item) {UserCostElement element = array.get(issuer);if (element != null) {element.add(item);} else {element = new UserCostElement(issuer);element.add(item);array.put(element.getIssuer(), element);}}/*** 输出全部* @return*/public List list() {return new ArrayList(array.values());}/*** 查找一个成员* @param siger 签名* @return 返回匹配的成员*/public UserCostElement find(Siger siger) {return array.get(siger);}/*** 判断是空* @return*/public boolean isEmpty() {return array.isEmpty();}/*** 有效单元数目* @return 整数*/public int size() {return array.size();}/* (non-Javadoc)* @see com.laxcus.echo.product.EchoProduct#duplicate()*/@Overridepublic CheckUserCostProduct duplicate() {return new CheckUserCostProduct(this);}/* (non-Javadoc)* @see com.laxcus.echo.product.EchoProduct#buildSuffix(com.laxcus.util.ClassWriter)*/@Overrideprotected void buildSuffix(ClassWriter writer) {writer.writeInt(array.size());for (UserCostElement e : array.values()) {writer.writeObject(e);}}/* (non-Javadoc)* @see com.laxcus.echo.product.EchoProduct#resolveSuffix(com.laxcus.util.ClassReader)*/@Overrideprotected void resolveSuffix(ClassReader reader) {int size = reader.readInt();for (int i = 0; i < size; i++) {UserCostElement element = new UserCostElement(reader);add(element.getIssuer(), element);}}}

最后,我们需要把它们整合起来,编写成计算机程序,投递给Laxcus计算机集群来处理,这里的代码就非常简单,只有以下几步:
1.生成命令 (这步上面已经演示)
2.生成一个异步监听接口,和命令一起,交给命令分派接口处理。
3.调用Laxcus分布式操作系统DSDK中的命令分派接口,把命令和异步监听器投递给它,DSDK代让命令分派接口投递给Laxcus集群处理。
4.异步监听接口收到反馈结果,解析CheckUsetCostProduct中的参数,结合计费算法,得出计费结果。
这些步骤集合起来,就是下面这样一段代码:

class CheckUserCostProductListener implements ProductListener {@Overridepublic void push(Object e) {boolean success = (e != null && e.getClass() == CheckUserCostProduct.class);if (!success) {// 不成功,做出错的处理return;}// 成功,提取返回参数,结束计费算法,得出计费结果}}// 1. 生成命令CheckUserCost cmd = new CheckUserCost();cmd.setAll(true);Siger siger = Laxkit.doSiger("tubex");cmd.addUser(siger);cmd.addExclude(new Naming("conduct"));long timestamp = CalendarGenerator.splitTimestamp("2022-12-1");cmd.setBeginTime(timestamp);timestamp = CalendarGenerator.splitTimestamp("2022-12-2");cmd.setEndTime(timestamp);// 2. 生成异步监听器,返回结果将投递给它处理CheckUserCostProductListener listner = new CheckUserCostProductListener();// 3. 生成交互适配器,在命令投递进入集群前出现错误,将由它来处理和显示MeetDisplayAdapter adapter = new MeetDisplayAdapter(listener);// 4. 调用系统API,把命令投递给集群处理CommandDispatcher dispatcher = PlatformKit.findListener(CommandDispatcher.class);dispatcher.submit(cmd, true, new CommandAuditorAdapter(), adapter);

上面这些代码通过编译,做成一个Laxcus分布式操作系统的应用软件,就可以运行了。
另外,如果是在Laxcus管理员桌面环境以外运行,那么就要把DSDK集成起来,并且连接进入Laxcus集群,才能执行上面的操作。
至此,一个简单的Laxcus云服务计费系统设计完成。有兴趣不妨去试试,把它“润”起来,看看你的Laxcus云服务有多少人在使用,他们在执行什么工作,消耗了多少计算机资源,也或者看看有什么改进工作要做吧。

相关内容

热门资讯

【MySQL】锁 锁 文章目录锁全局锁表级锁表锁元数据锁(MDL)意向锁AUTO-INC锁...
【内网安全】 隧道搭建穿透上线... 文章目录内网穿透-Ngrok-入门-上线1、服务端配置:2、客户端连接服务端ÿ...
GCN的几种模型复现笔记 引言 本篇笔记紧接上文,主要是上一篇看写了快2w字,再去接入代码感觉有点...
数据分页展示逻辑 import java.util.Arrays;import java.util.List;impo...
Redis为什么选择单线程?R... 目录专栏导读一、Redis版本迭代二、Redis4.0之前为什么一直采用单线程?三、R...
【已解决】ERROR: Cou... 正确指令: pip install pyyaml
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
Lock 接口解读 前置知识点Synchronized synchronized 是 Java 中的关键字,...
Win7 专业版安装中文包、汉... 参考资料:http://www.metsky.com/archives/350.htm...
3 ROS1通讯编程提高(1) 3 ROS1通讯编程提高3.1 使用VS Code编译ROS13.1.1 VS Code的安装和配置...
大模型未来趋势 大模型是人工智能领域的重要发展趋势之一,未来有着广阔的应用前景和发展空间。以下是大模型未来的趋势和展...
python实战应用讲解-【n... 目录 如何在Python中计算残余的平方和 方法1:使用其Base公式 方法2:使用statsmod...
学习u-boot 需要了解的m... 一、常用函数 1. origin 函数 origin 函数的返回值就是变量来源。使用格式如下...
常用python爬虫库介绍与简... 通用 urllib -网络库(stdlib)。 requests -网络库。 grab – 网络库&...
药品批准文号查询|药融云-中国... 药品批文是国家食品药品监督管理局(NMPA)对药品的审评和批准的证明文件...
【2023-03-22】SRS... 【2023-03-22】SRS推流搭配FFmpeg实现目标检测 说明: 外侧测试使用SRS播放器测...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
初级算法-哈希表 主要记录算法和数据结构学习笔记,新的一年更上一层楼! 初级算法-哈希表...
进程间通信【Linux】 1. 进程间通信 1.1 什么是进程间通信 在 Linux 系统中,进程间通信...
【Docker】P3 Dock... Docker数据卷、宿主机与挂载数据卷的概念及作用挂载宿主机配置数据卷挂载操作示例一个容器挂载多个目...