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

DBus快速入门

DBus快速入门

参考链接:

  1. 中文博客:

    https://www.e-learn.cn/topic/1808992

    https://blog.csdn.net/u011942101/article/details/123383195

    https://blog.csdn.net/weixin_44498318/article/details/115803936

    https://www.e-learn.cn/topic/1808992

    https://blog.csdn.net/Dontla/article/details/122530765

  2. D-Bus Specification:

    https://dbus.freedesktop.org/doc/dbus-specification.html

    https://pythonhosted.org/txdbus/dbus_overview.html

    https://dbus.freedesktop.org/doc/dbus-tutorial.html

本文主要记录一下我对dbus的认知,当然可能会存在一些错误,欢迎读者指正。

DBus安装

命令如下:

# 安装dbus
sudo apt-get install dbus# 安装d-feet工具,用于查看 session bus 和 system bus
sudo apt-get install d-feet# 安装glib2.0
sudo apt-get install libgtk2.0-dev# 安装 dbus-glib
apt-get install libdbus-glib-1-dev# for dbus-launch
apt install dbus-x11

c_cpp_properties.json配置:

主要注意includePath

{"configurations": [{"name": "Linux","includePath": ["${workspaceFolder}/**","/usr/include/dbus-1.0/","/usr/include/glib-2.0/","/usr/lib/x86_64-linux-gnu/glib-2.0/include/"],"defines": [],"compilerPath": "/usr/bin/clang","cStandard": "c17","cppStandard": "c++14","intelliSenseMode": "linux-clang-x64"}],"version": 4
}

DBus整体结构

DBus是基于本地套接字实现的IPC框架,可用于进程间的通信或进程与内核的通信。

这里贴一张官方提供的dbus整体架构图:

在这里插入图片描述

DBUS的优点:

  1. 因为DBUS主要应用在同一台机器上,不会跨主机进行IPC通信。所以使用二进制协议,省去序列化的代价。但是如果需要传递像字符串指针的话,就需要通过地址将字符串拷贝到Message中,所以或多或少还是存在一些序列化的过程。

  2. DBUS的“报文”在传递时,避免了往返的开销。并且支持异步操作。

  3. 报文以消息的方式传递而不是(类似于TCP)字节流。

  4. D-Bus 库的封装方式可以让开发人员利用其框架现有的对象/类型系统,而无需学习新的IPC的特点,然后重构他们的项目。

这里简单解释一下dbus整体架构图的一个交互流程:

在DBUS中,一个完整的IPC交互流程包括三个部分:Bus Daemon Process、Client Application Process、Server Application Process。Bus Daemon Process有两类:Session Bus、System Bus,这里本文主要讨论Session Bus,这两类Bus主要区别在于:Session Bus是主要负责应用程序之间的一个交互,而System Bus主要负责内核和应用程序之间的一个交互。Bus Daemon Process在两个应用程序交互之中起路由作用。从图中可以看到所有的应用程序和Bus Daemon Process的连接都是通过本地socket。

主要流程:

  1. app1(client)和app2(server)都通过Bus Daemon Process的套接字地址连接上去。

  2. app1请求一个叫com.app1.client的Bus Name,app2请求一个叫com.app2.server的Bus Name

  3. app1构造一个method calls消息,method calls消息至少包括:Dest Bus Name(目的地址,假设这里是com.app2.server)、Object Path、Interface Name 、Method Name(包括参数,这里假设是int add(int n1, int n2)),然后将消息报文发送给Bus Daemon Process。

  4. Bus Daemon Process根据消息的Dest Bus Name,将消息路由给app2。

  5. app2根据消息的Object Path、Interface Name 、Method Name调用相应的方法(add函数),然后根据返回值以及接收到的method calls消息封装成一条method returns消息,发回给Bus Daemon Process,进而路由给app1。

  6. app1接收到method returns消息后解析出里面的返回值,于此一次交互完成。

dbus中消息有四种类型:

  1. signals:信号,一般用于广播,不会有目的地址和返回值。

  2. method calls:方法调用,定向传播,有目的地址,可能有返回值。

  3. method returns:方法返回,简单理解就是method calls的返回值。

  4. errors:错误,简单理解就是错误码。

上面流程主要用到method calls、method returns两种消息类型。

梳理了一下dbus的交互流程,其实会发现dbus和RPC非常像。不同点在于dbus更像是一种本地专用的RPC。

dbus-daemon的地址保存在环境变量DBUS_SESSION_BUS_ADDRESS中,用于表示当前登录用户的session的dbus-daemon进程的地址,可以使用下面命令查看。

root@lunar-virtual-machine:~# echo $DBUS_SESSION_BUS_ADDRESS
unix:path=/run/user/0/bus

session bus由用户登录时dbus-launch脚本自动启动,当然,你也可以自己在终端启动一个bus-daemon,方便调试:

root@lunar-virtual-machine:~# DBUS_VERBOSE=1 dbus-daemon --session --print-address
unix:abstract=/tmp/dbus-49gl7TnTcs,guid=864158a61bb94df92e3e1ac866936bd1

然后将DBUS_SESSION_BUS_ADDRESS修改为:unix:abstract=/tmp/dbus-49gl7TnTcs,guid=864158a61bb94df92e3e1ac866936bd1,再启动应用程序即可连接到自己启动的dbus-daemon上。

DBus深入理解

先下载一个dbus实例:http://www.fmddlmyy.cn/down2/hello-dbus3-0.1.tar.gz

四步构建并运行dbus服务器

./autogen.sh
./configure
make
./example-service

然后另起一个终端,执行d-feet命令,会弹出一个窗口:

在这里插入图片描述

双击Methods下的Add方法,会弹出一个对话框,输入参数并确认后你就会看到相加的结果。这个具体的交互过程和。上面我们分析的流程是一样的。

下面通过该窗口逐步了解DBUS的相关概念。

Bus Name: 应用和消息总线的连接标识符,有两类,包括:well-known name(熟知名)和unique name(唯一名)

well-known name形如:”org.fmddlmyy.Test“

unique name形如:”:1.114“

well-known name可以被多个连接(非同时)所拥有,unique name在所有连接中是唯一的。一个连接可以同时拥有well-known name和unique name,well-known name,但是唯一名是必须的,但熟知名不是必须的。well-known name可以类比于网络中的域名,unique name可以类比于网络中的IP地址。

当多个应用连接到消息总线,要求提供同一个公共名的服务。消息总线会把这些连接排在链表中,并选择一个连接提供公共名代表的服务。可以说这个提供服务的连接拥有了这个公共名。如果这个连接退出了,消息总线会从链表中选择下一个连接提供服务。

Native Objects and Object Paths: Native Objects类似java中的java.lang.Object、QT中的QObject等等。在最底层的dbus中纯在形式只是一个字符串。

Object Paths形如:”/TestObject“

Methods and Signals(Name): Methods表示被具体调用的方法,而Signals就是信号。Method可以有返回值,Signals一定没有返回值,此外,Signals可以进行广播,应用程序可以向bus订阅要接收的信号的Interface,一旦注册,只要DBUS收到信号,就会根据的信号的接口,将信号广播给相应的应用程序。在最底层的dbus中纯在形式只是一个字符串。

Interfaces(Name): 相当于C++中的纯虚类。每个对象都有一个或者多个接口,一个接口就是多个方法和信号的集合。在最底层的dbus中纯在形式只是一个字符串。

形如:
org.fmddlmyy.Test.Basic

org.freedesktop.DBus.Introspectable (由消息总线提供的标准接口

org.freedesktop.DBus.Properties (由消息总线提供的标准接口

在基于C实现的最底层的dbus中的对象、接口、方法、信号等概念可能很难去理解,我最开始也是比较困惑,但是如果你对dbus框架感兴趣的话,可以去了解一下dbus在面向对象的语言在的用法,比如dbus-c++,他里面的这些概念就非常直观。

因为D-BUS的底层接口没有对象相关概念,所以它的Object、Methods、Signals、Interfaces都是以字符串的形式标识。在面向对象的语言对dbus进行封装后,我们可以通过编写XML来定义接口和方法,并且通过我们编写的XML来生成相应的接口代码。接口里面就会包括方法和信号的定义。用户只用去继承这些接口,然后去实现它里面的方法即可。当然用户还需要去根据这些接口去定义相应的对象

这里我故意漏掉了一个概念—Proxies: 代理对象用来表示其他的remote object。当触发了proxy对象的method时,将会在D-Bus上发送一个method_call的消息,并等待答复,根据答复返回。总线上的对象一般通过代理来访问。总线上的对象位于客户进程以外,而客户可以调用本地接口与对象通信,此时,本地接口充当了代理的角色。当触发了代理对象的方法时,将会在D-Bus上发送一个method_call的消息,并等待答复返回,就象使用一个本地对象一样。重点关注最后一句话!代理能够使用户去调用一个本地接口,该本地接口代替你向总线发消息,去调用另一个进程方法,并且接收返回值。简而言之,代理的概念还是要配合面向对象的语言对dbus的封装才好理解。

比如不用代理:

Message message = new Message("/remote/object/path", "MethodName", arg1, arg2); 
Connection connection = getBusConnection();           
connection.send(message);           
Message reply = connection.waitForReply(message);           
if (reply.isError()) {                         
}
else {              Object returnValue = reply.getReturnValue();           
} 

用代理就是:

Proxy proxy = new Proxy(getBusConnection(), "/remote/object/path");           
Object returnValue = proxy.MethodName(arg1, arg2);

dbus规定了一个统一的接口:org.freedesktop.DBus.Introspectable,通过该接口的Introspect方法,可以递归遍历一个连接的对象树,包括server的接口和其方法、信号。另外因为Bus Daemon Process也属于进程,应用进程也可以请求Bus Daemon Process的接口和方法。Bus Daemon Process的Bus Name为:org.freedesktop.DBus,利用总线的org.freedesktop.DBus.Introspectable.Introspect方法我们可以查看消息总线对象支持的接口以及其方法、信号。此外我们还可以调用总线的\对象的org.freedesktop.DBus.ListNames方法,来获取消息总线上已连接的所有连接名,包括所有公共名和唯一名。

这些内容具体细节在https://www.e-learn.cn/topic/1808992有深入讲解,感兴趣的读者可以去看一看。

dbus是支持提供server的应用程序按需启动,在client请求的server应用程序没有启动时,daemon bus首先会依据配置起一个server应用程序。通过总线的/对象的org.freedesktop.DBus.ListActivatableNames方法,可以获取所有能够自启动的服务。

要想让自己的server应用程序自启动,需要添加一个配置文件,如下:

vim /usr/share/dbus-1/services/org.fmddlmyy.Test.service# [D-BUS Service]
# Name=org.fmddlmyy.Test    # 定义Bus Name
# Exec=/home/lvjie/work/dbus/hello-dbus3-0.1/src/example-service    # 提供可执行程序的路径

dbus的方法参数、返回值类型可以是基本类型,也可以是复合类型,具体语法可以参考:https://pythonhosted.org/txdbus/dbus_overview.html。

这里简单列举一下复合类型:

数组:

ai - 32位整型数组

a(ii) - 元素类型为两个32位整型的结构体的数组

aai - 元素类型为32位整型的数组的数组

字典:

a{ss} - key为string,value为string

a{is} - key为32位整数 ⇒ value为string

a{s(ii)} - key为string ⇒ value为包含2个32位整数的数组

a{sa{ss}} - key为string ⇒ value也是字典。

DBus示例代码

Server Application:不断处理来自Client Application的方法调用。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus.h>
#include <unistd.h>void reply_to_method_call(DBusMessage *msg, DBusConnection *conn){DBusMessage *reply;DBusMessageIter arg;char *param = NULL;dbus_bool_t stat = TRUE;dbus_uint32_t level = 2010;dbus_uint32_t serial = 0;//从msg中读取参数if(!dbus_message_iter_init(msg, &arg))printf("Message has noargs\n");else if(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_STRING)printf("Arg is notstring!\n");elsedbus_message_iter_get_basic(&arg, &param);if(param == NULL) return;//创建返回消息replyreply = dbus_message_new_method_return(msg);//在返回消息中填入两个参数,和信号加入参数的方式是一样的。这次我们将加入两个参数。dbus_message_iter_init_append(reply, &arg);if(!dbus_message_iter_append_basic(&arg, DBUS_TYPE_BOOLEAN, &stat)){printf("Out ofMemory!\n");exit(1);}if(!dbus_message_iter_append_basic(&arg, DBUS_TYPE_UINT32, &level)){printf("Out ofMemory!\n");exit(1);}//发送返回消息if(!dbus_connection_send(conn, reply, &serial)){printf("Out of Memory\n");exit(1);}dbus_connection_flush(conn);dbus_message_unref(reply);
}void listen_dbus()
{DBusMessage *msg;DBusMessageIter arg;DBusConnection *connection;DBusError err;int ret;char *sigvalue;dbus_error_init(&err);//创建于session D-Bus的连接connection = dbus_bus_get(DBUS_BUS_SESSION, &err);if(dbus_error_is_set(&err)){fprintf(stderr, "ConnectionError %s\n", err.message);dbus_error_free(&err);}if(connection == NULL)return;//设置一个BUS name:test.wei.destret = dbus_bus_request_name(connection, "test.wei.dest", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);if(dbus_error_is_set(&err)){fprintf(stderr, "Name Error%s\n", err.message);dbus_error_free(&err);}if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)return;//要求监听某个singal:来自接口test.signal.Type的信号dbus_bus_add_match(connection, "type='signal', interface='test.signal.Type'", &err);dbus_connection_flush(connection);if(dbus_error_is_set(&err)){fprintf(stderr, "Match Error%s\n", err.message);dbus_error_free(&err);}while(1){dbus_connection_read_write(connection, 0);msg = dbus_connection_pop_message(connection);if(msg == NULL){sleep(1);continue;}if(dbus_message_is_signal(msg, "test.signal.Type", "Test")){if(!dbus_message_iter_init(msg, &arg))fprintf(stderr, "Message Has no Param");else if(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_STRING)fprintf(stderr, "Param isnot string");else{dbus_message_iter_get_basic(&arg, &sigvalue);fprintf(stdout, "[method_call]Got Singal withvalue : %s\n", sigvalue);}}else if(dbus_message_is_method_call(msg, "test.method.Type", "Method")){//我们这里面先比较了接口名字和方法名字,实际上应当现比较路径if(strcmp(dbus_message_get_path(msg), "/test/method/Object") == 0){reply_to_method_call(msg, connection);fprintf(stdout, "[method_call]Got method_call, reply to it!\n");}}dbus_message_unref(msg);}
}int main(int argc, char **argv){listen_dbus();return 0;
}

Client Application:发送Method Call消息或者信号。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus.h>
#include <unistd.h>//建立与session D-Bus daemo的连接,并设定连接的名字,相关的代码已经多次使用过了
DBusConnection* connect_dbus()
{DBusError err;DBusConnection *connection;int ret;//Step 1: connecting session busdbus_error_init(&err);connection = dbus_bus_get(DBUS_BUS_SESSION, &err);if(dbus_error_is_set(&err)){fprintf(stderr, "ConnectionErr : %s\n", err.message);dbus_error_free(&err);}if(connection == NULL)return NULL;//step 2: 设置BUS name,也即连接的名字。ret = dbus_bus_request_name(connection, "test.wei.source", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);if(dbus_error_is_set(&err)){fprintf(stderr, "Name Err :%s\n", err.message);dbus_error_free(&err);}if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)return NULL;return connection;
}void send_a_method_call(DBusConnection *connection,char *param)
{DBusError err;DBusMessage *msg;DBusMessageIter arg;DBusPendingCall *pending;dbus_bool_t *stat;dbus_uint32_t *level;dbus_error_init(&err);//针对目的地地址,请参考图,创建一个method call消息。Constructs a new message to invoke a method on a remote object.msg = dbus_message_new_method_call("test.wei.dest", "/test/method/Object", "test.method.Type", "Method");if(msg == NULL){fprintf(stderr, "MessageNULL");return;}//为消息添加参数。Appendargumentsdbus_message_iter_init_append(msg, &arg);if(!dbus_message_iter_append_basic(&arg, DBUS_TYPE_STRING, &param)){fprintf(stderr, "Out of Memory!");exit(1);}//发送消息并获得reply的handle。Queues amessage to send, as withdbus_connection_send() , but also returns aDBusPendingCall used to receive a reply to the message.if(!dbus_connection_send_with_reply(connection, msg, &pending, -1)){fprintf(stderr, "Out of Memory!");exit(1);}if(pending == NULL){fprintf(stderr, "Pending CallNULL: connection is disconnected ");dbus_message_unref(msg);return;}dbus_connection_flush(connection);dbus_message_unref(msg);//waiting a reply,在发送的时候,已经获取了methodreply的handle,类型为DBusPendingCall。// block until we recieve a reply, Block until the pendingcall is completed.dbus_pending_call_block(pending);//get the reply message,Gets thereply, or returns NULL if none has been received yet.msg = dbus_pending_call_steal_reply(pending);if (msg == NULL) {fprintf(stderr, "ReplyNull\n");exit(1);}// free the pendingmessage handledbus_pending_call_unref(pending);// read the parametersif(!dbus_message_iter_init(msg, &arg))fprintf(stderr, "Message hasno arguments!\n");else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_BOOLEAN)fprintf(stderr, "Argument isnot boolean!\n");elsedbus_message_iter_get_basic(&arg, &stat);if (!dbus_message_iter_next(&arg))fprintf(stderr, "Message hastoo few arguments!\n");else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_UINT32 )fprintf(stderr, "Argument isnot int!\n");elsedbus_message_iter_get_basic(&arg, &level);printf("Got Reply: %d,%d\n", stat, level);dbus_message_unref(msg);
}int send_a_signal(DBusConnection *connection, char *sigvalue)
{DBusError err;DBusMessage *msg;DBusMessageIter arg;dbus_uint32_t  serial = 0;int ret;//步骤3:发送一个信号//根据图,我们给出这个信号的路径(即可以指向对象),接口,以及信号名,创建一个Messageif((msg = dbus_message_new_signal("/test/signal/Object", "test.signal.Type", "Test"))== NULL){fprintf(stderr, "MessageNULL\n");return -1;}//给这个信号(messge)具体的内容dbus_message_iter_init_append(msg, &arg);if(!dbus_message_iter_append_basic(&arg, DBUS_TYPE_STRING, &sigvalue)){fprintf(stderr, "Out OfMemory!\n");return -1;}//步骤4: 将信号从连接中发送if(!dbus_connection_send(connection, msg, &serial)){fprintf(stderr, "Out of Memory!\n");return -1;}dbus_connection_flush(connection);printf("Signal Send\n");//步骤5: 释放相关的分配的内存。dbus_message_unref(msg);return 0;
}int main(int argc, char **argv)
{DBusConnection *connection;connection = connect_dbus();if(connection == NULL)return -1;if (argc > 1) {send_a_method_call(connection,"Hello, D-Bus");} else {send_a_signal(connection, "Hello,world!");}return 0;
}
gcc -Wall -o server server.c -ldbus-1 -I/usr/include/dbus-1.0/ -I/usr/include/glib-2.0/ -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/gcc -Wall -o client client.c -ldbus-1 -I/usr/include/dbus-1.0/ -I/usr/include/glib-2.0/ -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/

结果如下:

在这里插入图片描述


本章完结

相关文章:

DBus快速入门

DBus快速入门 参考链接&#xff1a; 中文博客&#xff1a; https://www.e-learn.cn/topic/1808992 https://blog.csdn.net/u011942101/article/details/123383195 https://blog.csdn.net/weixin_44498318/article/details/115803936 https://www.e-learn.cn/topic/1808992 htt…...

SQL Server 设置端口号:详细步骤与注意事项

目录 一、了解SQL Server端口号的基础知识 1.1 默认端口号 1.2 静态端口与动态端口 二、使用SQL Server配置管理器设置端口号 2.1 打开SQL Server配置管理器 2.2 定位到SQL Server网络配置 2.3 修改TCP/IP属性 2.4 重启SQL Server服务 三、注意事项 3.1 防火墙设置 3…...

Python面试题:结合Python技术,如何使用NetworkX进行复杂网络分析

NetworkX 是一个强大的 Python 库&#xff0c;用于创建、操作和研究复杂网络的结构、动力学和功能。它提供了丰富的功能来处理图和网络数据&#xff0c;适合用于复杂网络分析。以下是使用 NetworkX 进行复杂网络分析的基本步骤&#xff1a; 安装 NetworkX&#xff1a; pip inst…...

【C#/C++】C#调C++的接口,给C++传结构体数组

C#调C的接口&#xff0c;给C传结构体数组 1、背景2、实现 1、背景 C#软件创建了一个结构体数组用来存储图像的区域信息&#xff0c;分别是矩形框的左上像素的xy坐标和矩形框右下像素的xy坐标。需要传入给调用的C函数的参数列表中&#xff0c;我们选择使用C#传入一个结构体数组…...

ctfshow SSTI注入 web369--web372

web369 这把request过滤了&#xff0c;只能自己拼字符了 ""[[__clas,s__]|join] 或者 ""[(__clas,s__)|join] 相当于 ""["__class__"]举个例子&#xff0c;chr(97) 返回的是字符 a&#xff0c;因为 97 是小写字母 a 的 Unicode 编码…...

Llama + Dify,在你的电脑搭建一套AI工作流

theme: smartblue 点赞 关注 收藏 学会了 本文简介 最近字节在推Coze&#xff0c;你可以在这个平台制作知识库、制作工作流&#xff0c;生成一个具有特定领域知识的智能体。 那么&#xff0c;有没有可能在本地也部署一套这个东西呢&#xff1f;这样敏感数据就不会泄露了&…...

洛谷 P9854 [CCC 2008 J1] Body Mass Index

这题让我们计算出 BMI 值&#xff0c;随后判断属于哪个等级。 BMI 值计算公式&#xff1a; ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​。 BMI 范围 对应信息 …...

Redis面试三道题目

针对Redis的面试题&#xff0c;我将从简单到困难给出三道题目&#xff0c;并附上参考答案的概要。 1. 简单题&#xff1a;请简述Redis是什么&#xff0c;以及它的主要优点。 参考答案&#xff1a; Redis简介&#xff1a;Redis是一个开源的、使用ANSI C语言编写、支持网络、可…...

redis的使用场景-分布式锁

使用redis的setnx命令放入数据并用此数据当锁完成业务&#xff08;但是如果用户操作途中出现异常导致超出指定时间会出现问题&#xff09; Service public class StockService {Autowiredprivate StockDao stockDao; //mapper注入Autowiredprivate StringRedisTemplate redisT…...

知识库系统全解析:2024年最佳9款

本文将分享9款优质团队知识库管理工具&#xff1a;PingCode、Worktile、石墨文档、语雀、Wolai 我来、有道云笔记、飞书文档、Confluence、Notion。 在追求高效团队运作的今天&#xff0c;掌握和整合知识成为了企业不可或缺的需求。但面对市场上琳琅满目的知识库管理工具&#…...

猫头虎分享:Numpy知识点一文带你详细学习np.random.randn()

&#x1f42f; 猫头虎分享&#xff1a;Numpy知识点一文带你详细学习np.random.randn() 摘要 Numpy 是数据科学和机器学习领域中不可或缺的工具。在本篇文章中&#xff0c;我们将深入探讨 np.random.randn()&#xff0c;一个用于生成标准正态分布的强大函数。通过详细的代码示…...

QT 关于QTableWidget的常规使用

目录 一、初始化 二、封装功能用法 三、结语 一、初始化 1、设置表头 直接在ui设计界面修改或者使用QT封装的函数修改&#xff0c;代码如下&#xff1a; QStringList recList {"第一列", "第二列", "第三列"}; ui->tableWidget->setH…...

PyCharm 常用 的插件

Material Theme UI Lite&#xff1a;‌提供多种不同的页面风格&#xff0c;‌为PyCharm界面增添个性化元素。‌Chinese (Simplified) Language Pack&#xff1a;‌为中文用户提供简体中文的界面、‌菜单、‌提示信息&#xff0c;‌提升使用体验。‌Tabnine&#xff1a;‌基于人…...

理解 HTTP 请求中 Query 和 Body 的异同

本文将深入探讨HTTP请求中的两个关键要素&#xff1a;查询参数&#xff08;Query&#xff09;和请求体&#xff08;Body&#xff09;。我们将阐明它们之间的差异&#xff0c;并讨论在何种情况下使用每一种。 HTTP 请求概述 HTTP 请求是客户端&#xff08;如浏览器&#xff09…...

【AI大模型】 企业级向量数据库的选择与实战

前言 ChatGPT4相比于ChatGPT3.5,有着诸多不可比拟的优势&#xff0c;比如图片生成、图片内容解析、GPTS开发、更智能的语言理解能力等&#xff0c;但是在国内使用GPT4存在网络及充值障碍等问题&#xff0c;如果您对ChatGPT4.0感兴趣&#xff0c;可以私信博主为您解决账号和环境…...

LangChain开发框架并学会对大型预训练模型进行微调(fine-tuning)

要掌握LangChain开发框架并学会对大型预训练模型进行微调&#xff08;fine-tuning&#xff09;&#xff0c;你需要理解整个过程从数据准备到最终部署的各个环节。下面是这一流程的一个概览&#xff0c;并提供了一些关键步骤和技术点&#xff1a; 1. LangChain开发框架简介 La…...

VMware安装(有的时候启动就蓝屏建议换VM版本)

当你开始使用虚拟化技术来管理和运行多个操作系统时&#xff0c;VMware 是一个强大且广泛使用的选择。本篇博客将指导你如何安装 VMware Workstation Pro&#xff0c;这是一个功能强大的虚拟机软件&#xff0c;适用于个人和专业用户。 一、下载 VMware Workstation Pro 访问官网…...

AV1技术学习:Quantization

量化是对变换系数进行&#xff0c;并将量化索引熵编码。AV1的量化参数 QP 的取值范围是0 ~ 255。 一、Quantization Step Size 在给定的 QP 下&#xff0c;DC 系数的量化步长小于 AC 系数的量化步长。DC 系数和 AC 系数从 QP 到量化步长的映射如下图所示。当 QP 为 0 时&…...

vllm部署记录

1. pip安装 pip install vllm 下载模型在huggingface.co 注意在modelscope上的这个opt-125m好像不行了,我git不下来报错 启动服务 vllm serve opt-125m --model opt-125m --port 8888 第一个opt-125m是名字,可以在vllm支持的模型中查到,第二个是模型存放文件夹及其路径…...

HTML前端 盒模型及常见的布局 流式布局 弹性布局 网格布局

CSDN的文章没有“树状目录管理”&#xff0c;所以我在这里整理几篇相关的博客链接。 操作有些麻烦。 CSS 两种盒模型 box-sizing content-box 和 border-box 流式布局 flow layout 弹性布局 flex layout HTML CSS 网格布局 grid layout HTML CSS...

网络安全 DVWA通关指南 DVWA Command Injection(命令注入)

DVWA Command Injection&#xff08;命令注入&#xff09; 文章目录 DVWA Command Injection&#xff08;命令注入&#xff09;LowMediumHighImpossible Low 1、分析网页源代码 <?php// 当表单提交按钮&#xff08;Submit&#xff09;被触发时执行以下代码 if (isset($_P…...

VUE3学习第三篇:报错记录

1、在我整理好前端代码框架后&#xff0c;而且也启动好了对应的后台服务&#xff0c;访问页面&#xff0c;正常。 2、报错ReferenceError: defineModel is not defined 学到这里报错了 在vue网站的演练场&#xff0c;使用没问题 但是在我自己的代码里就出问题了 3、watchEffec…...

CentOS怎么关闭自动锁屏?

禁止自动锁屏 有时候几分钟不用Centos&#xff0c;系统就自动锁屏了&#xff0c;这是一种安全措施&#xff0c;防止别人趁你不在时使用你的系统。但对于大部分人而言&#xff0c;这是没有必要的&#xff0c;尤其是Centos虚拟机&#xff0c;里面没啥重要的东西&#xff0c;每次…...

vscode 环境

这张截图显示的是在VS Code&#xff08;Visual Studio Code&#xff09;中选择Python解释器的界面。不同的Python解释器及其虚拟环境列出了可选项&#xff0c;用户可以根据需要选择合适的解释器来运行Python代码。以下是对截图中信息的详细解释&#xff1a; 解释器选择界面 当…...

浏览器自动化测试工具selenium——爬虫操作记录

selenium——是一款web自动化测试框架&#xff0c;其能模拟正常的用户操作&#xff0c;比如点击。但selenium并不是浏览器&#xff0c;没有执行js和解析html/css的能力&#xff0c;因此selenium需要和浏览器配合使用。 因为selenium可以模仿用户行为&#xff0c;因此selenium也…...

微信小程序配置访问服务器失败所发现的问题及解决方案

目录 事前现象问题1&#xff1a;问题现象&#xff1a;问题分析&#xff1a; 问题2&#xff1a;问题现象&#xff1a;问题分析&#xff1a;解决方案&#xff1a; 事后现象 事前现象 问题1&#xff1a; 问题现象&#xff1a; 在本地调试时&#xff0c;一切顺利&#xff0c;但一…...

javaEE(1)

一. Web开发概述 Web开发:指的是从网页中向后端程序发送请求,与后端程序进行交互 Web服务器:是一种软件,向浏览器等Web客户端提供文档等数据,实现数据共享,它是一个容器,是一个连接用户和程序之间的中间键 二. Web开发环境搭建 我们要实现前后端交互,首先需要中间键Web服务…...

极简Springboot+Mybatis-Plus+Vue零基础萌新都看得懂的分页查询(富含前后端项目案例)

目录 springboot配置相关 依赖配置 yaml配置 MySQL创建与使用 &#xff08;可拿软件包项目系统&#xff09; 创建数据库 创建数据表 mybatis-plus相关 Mapper配置 ​编辑 启动类放MapperScan 启动类中配置 添加config配置文件 Springboot编码 实体类 mapperc(Dao…...

IPython的Bash之舞:%%bash命令全解析

IPython的Bash之舞&#xff1a;%%bash命令全解析 IPython的%%bash魔术命令为Jupyter Notebook用户提供了一种在单元格中直接执行Bash脚本的能力。这个特性特别适用于需要在Notebook中运行系统命令或Bash特定功能的场景。本文将详细介绍如何在IPython中使用%%bash命令&#xff…...

ST Stellar-E SR5E1 22KW OBC combo 3KW DC-DC汽车充电器解决方案

对于全球的环境保护意识抬头&#xff0c;全球的汽车产业慢慢步入电动化的时代&#xff0c;以减少碳排放。整车系统主要是由电池、电驱、电控的三电所构成&#xff0c;其中电池系统是整车的动力来源&#xff0c;而对电池充电的OBC系统更甚重要。一具高度安全性且高效的OBC系统&a…...