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

【笔记】Spring Cloud Gateway 实现 gRPC 代理

Spring Cloud Gateway 在 3.1.x 版本中增加了针对 gRPC 的网关代理功能支持,本片文章描述一下如何实现相关支持.本文主要基于 Spring Cloud Gateway 的 官方文档 进行一个实践练习。有兴趣的可以翻看官方文档。

在这里插入图片描述
由于 Grpc 是基于 HTTP2 协议进行传输的,因此 Srping Cloud Gateway 在支持了 HTTP2 的基础上天然支持对 Grpc 服务器的代理,只需要在现有代理基础上针对 grpc 协议进行一些处理即可。

以下为实现步骤,这里提供了示例代码,可以按需取用.

生成服务器证书

由于 Grpc 协议使用了 Http2 作为通信协议, Http2 在正常情况下是基于 TLS 层上进行通信的,这就要求我们需要配置服务器证书,这里为了测试,使用脚本生成了一套 CA 证书:

#!/bin/bash
# 指定生成证书的目录
dir=$(dirname "$0")/../resources/x509
[ -d "$dir" ] && find "$dir" -type f -exec rm -rf {} \;
mkdir -p "$dir"
pushd "$dir" || exit
# 生成.key  私钥文件 和 csr 证书签名请求文件
openssl req -new -nodes -sha256 -newkey rsa:2048 -keyout ca.key -out ca.csr \
-subj "/C=CN/ST=Zhejiang/L=Hangzhou/O=Ghimi Technology/OU=Ghimi Cloud/CN=ghimi.top"
# 生成自签名 .crt 证书文件
openssl x509 -req -in ca.csr -key ca.key -out ca.crt -days 3650
# 生成服务器私钥文件 和 csr 证书请求文件(私钥签名文件)
openssl req -new -nodes -sha256 -newkey rsa:2048 -keyout server.key -out server.csr \
-subj "/C=CN/ST=Zhejiang/L=Hangzhou/O=Ghimi Technology/OU=Ghimi Blog/CN=blog.ghimi.top"
# 3. 生成 server 证书,由 ca证书颁发
openssl x509 -req -in server.csr -out server.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -extensions SAN \
-extfile <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:dns.ghimi.top,IP:127.0.0.1,IP:::1"))
# 将 crt 证书转换为 pkcs12 格式,生成 server.p12 文件,密码 123456
openssl pkcs12 -export -in server.crt -inkey server.key -CAfile ca.crt \
-password pass:123456 -name server -out server.p12
# 导出服务器证书和证书私钥为 java keystore 格式 server.jks 为最终的导出结果 密码 123456
keytool -importkeystore -srckeystore server.p12 -destkeystore server.jks \
-srcstoretype pkcs12 -deststoretype jks -srcalias server -destalias server \
-deststorepass 123456 -srcstorepass 123456
# 将 ca 证书导入到 server.jks 中
keytool -importcert -keystore server.jks -file ca.crt -alias ca -storepass 123456 -noprompt
popd || exit

构建 Grpc 服务

首先我们需要创建一个 Maven 工程,并编写 gRPC 相关的服务器代码:

添加 gRPC 所需要的相关依赖:

<!-- grpc 关键依赖-->
io.grpc:grpc-netty-shaded:jar:1.64.0:runtime -- module io.grpc.netty.shaded [auto]
io.grpc:grpc-protobuf:jar:1.64.0:compile -- module io.grpc.protobuf [auto]
io.grpc:grpc-stub:jar:1.64.0:compile -- module io.grpc.stub [auto]
io.grpc:grpc-netty:jar:1.64.0:compile -- module io.grpc.netty [auto]

用 protobuf 生成一个 Java gRPC模板:

syntax = "proto3";
option java_multiple_files = true;
option java_package = "service";message HelloReq {string name = 1;
}
message HelloResp {string greeting = 1;
}
service HelloService {rpc hello(HelloReq) returns (HelloResp);
}

然后在 pom.xml 添加 prptobuf 生成插件:

<!-- project.build.plugins -->
<plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:3.25.1:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.64.0:exe:${os.detected.classifier}</pluginArtifact><!--设置grpc生成代码到指定路径--><!--<outputDirectory>${project.build.sourceDirectory}</outputDirectory>--><!--生成代码前是否清空目录--><clearOutputDirectory>true</clearOutputDirectory></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions>
</plugin>

注意在指定 protoc 的版本时要和上面 grpc 依赖的 protobuf 版本保持一致,否则可能会出现类找不到的报错。
在这里插入图片描述
然后执行执行 Maven 命令生成 Protobuf 对应的 Java 代码:

mvn protobuf:compile protobuf:compile-custom

之后就可以基于生成的 Protobuf Java 代码编写一个 gRPC Server 了 :

public static void main(String[] args) throws IOException, InterruptedException {TlsServerCredentials.Builder tlsBuilder = TlsServerCredentials.newBuilder();File serverCert = new ClassPathResource("/x509/server.crt").getFile();File serverKey = new ClassPathResource("/x509/server.key").getFile();File caCert = new ClassPathResource("/x509/ca.crt").getFile();ServerCredentials credentials  = tlsBuilder.trustManager(caCert).keyManager(serverCert, serverKey).build();// ServerCredentials credentials = InsecureServerCredentials.create(); // 不建议使用,非常坑Server server = Grpc.newServerBuilderForPort(443, credentials).addService(new HelloImpl()).build();server.start().awaitTermination();
}static class HelloImpl extends HelloServiceGrpc.HelloServiceImplBase {@Overridepublic void hello(HelloReq request, StreamObserver<HelloResp> responseObserver) {String msg = "hello " + request.getName() + " from server";System.out.println("server received a req,reply: " + msg);HelloResp res = HelloResp.newBuilder().setGreeting(msg).build();responseObserver.onNext(res);responseObserver.onCompleted();}
}

尝试启动 GrpcServer ,检查端口是否已被监听,当前端口绑定在 443 上,这里 GrpcServer 的服务器证书一定要配置.

编写 GrpcClient 代码:

public static void main(String[] args) throws InterruptedException, IOException {// 当服务器配置了证书时需要指定 ca 证书TlsChannelCredentials.Builder tlsBuilder = TlsChannelCredentials.newBuilder();File caCert = new ClassPathResource("/x509/ca.crt").getFile();ChannelCredentials credentials = tlsBuilder.trustManager(caCert).build();// 不做服务器证书验证时使用这个// ChannelCredentials credentials = InsecureChannelCredentials.create();ManagedChannelBuilder<?> builder = Grpc.newChannelBuilder("127.0.0.1:7443", credentials);ManagedChannel channel = builder.build();HelloServiceGrpc.HelloServiceBlockingStub stub = HelloServiceGrpc.newBlockingStub(channel);service.HelloReq.Builder reqBuilder = service.HelloReq.newBuilder();HelloResp resp = stub.hello(reqBuilder.setName("ghimi").build());System.out.printf("success greeting from server: %s", resp.getGreeting());channel.shutdown().awaitTermination(5, TimeUnit.MINUTES);
}

执行 GrpcClient,调用 443 端口的 GrpcServer 查看执行效果:
在这里插入图片描述
现在我们就可以开发 Spring Cloud Gateway 了,首先添加依赖,我这里添加了 spring-cloud-starter-gateway:3.1.9 版本(为了适配 Java8,已经升级 Java11 的可以提升至更高版本)。

org.springframework.cloud:spring-cloud-starter-gateway:3.1.9

编写 GrpcGateway 启动类:

@SpringBootApplication
public class GrpcGateway {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(GrpcGateway.class, args);}
}

先不做配置尝试运行一下,看下是否能够正常运行:
在这里插入图片描述
可以看到成功监听到了 8080 端口,这是 Spring Cloud Gateway 的默认监听端口,现在我们在 /src/main/resources/ 目录下添加 application.yml 配置,配置代理 grpc 端口:

server:port: 7443 #端口号http2:enabled: truessl:enabled: truekey-store: classpath:x509/server.p12key-store-password: 123456key-store-type: pkcs12key-alias: server
spring:application:name: scg_grpccloud:gateway: #网关路由配置httpclient:ssl:use-insecure-trust-manager: true
#          trustedX509Certificates:
#            - classpath:x509/ca.crtroutes:- id: user-grpc #路由 id,没有固定规则,但唯一,建议与服务名对应uri: https://[::1]:443 #匹配后提供服务的路由地址predicates:#以下是断言条件,必选全部符合条件- Path=/**               #断言,路径匹配 注意:Path 中 P 为大写- Header=Content-Type,application/grpcfilters:- AddResponseHeader=X-Request-header, header-value

添加 application.yml 后,重启 Spring Cloud Gateway 尝试用 GrpcClient 调用 7443 代理端口,可以看到请求成功:
在这里插入图片描述

报错分析

GrpcServer 和 GrpcClient 如果都配置了 InsecureServerCredentials 的情况下, GrpcClient 可以直接调用 GrpcServer 成功:

GrpcServer

TlsServerCredentials.Builder tlsBuilder = TlsServerCredentials.newBuilder();
ServerCredentials credentials = InsecureServerCredentials.create(); // 配置通过 h2c(http2 clear text) 协议访问
Server server = Grpc.newServerBuilderForPort(443, credentials).addService(new HelloImpl()).build();
server.start().awaitTermination();

GrpcClient

ChannelCredentials credentials = InsecureChannelCredentials.create(); // 通过 h2c 协议访问 GrpcServer
tlsBuilder.requireFakeFeature();
ManagedChannelBuilder<?> builder = Grpc.newChannelBuilder("127.0.0.1:443", credentials);
ManagedChannel channel = builder.build();
HelloServiceGrpc.HelloServiceBlockingStub stub = HelloServiceGrpc.newBlockingStub(channel);
service.HelloReq.Builder reqBuilder = service.HelloReq.newBuilder();
HelloResp resp = stub.hello(reqBuilder.setName("ghimi").build());
System.out.printf("success greeting from server: %s\n", resp.getGreeting());
channel.shutdown().awaitTermination(5, TimeUnit.MINUTES);

此时使用 GrpcClient 调用 GrpcServer ,可以调用成功:
在这里插入图片描述

但是,如果中间添加了 Spring Cloud Gateway 的话, Grpc Server 和 Grpc Client 就都不能使用 InsecureCredentials 了, Spring Cloud Gateway 在这种场景下无论与 client 还是和 server 通信都会由于不识别的协议格式而报错:
在这里插入图片描述

如果 GrpcServer 没有配置服务器证书而是使用了 InsecureServerCredentials.create() ,GrpcClient 虽然不使用证书访问能够直接验证成功,但是如果中间通过 GrpcGateway 的话这种机制就有可能出现问题,因为 GrpcGateway 与 GrpcServer 之间的通信是基于 Http2 的,而非 Grpc 特定的协议,在 GrpcServer 没有配置服务器证书的情况下处理的包可能会导致 GrpcGateway 无法识别,但是如果 GrpcServer 配置了证书后 GrpcGateway 就能够正常验证了。

GrpcServer 在没有配置证书的情况下通过 Srping Cloud Gateway 的方式进行代理,并且 Spring Cloud Gateway 的 spring.cloud.gateway.http-client.ssl.use-insecure-trust-manager=true 的场景下 GrpcClient 访问 Spring Cloud Gateway 会报错:

GrpcClient 报错信息:

Exception in thread "main" io.grpc.StatusRuntimeException: UNKNOWN: HTTP status code 500
invalid content-type: application/json
headers: Metadata(:status=500,x-request-header=header-value,content-type=application/json,content-length=146)
DATA-----------------------------
{"timestamp":"2024-06-28T13:18:03.455+00:00","path":"/HelloService/hello","status":500,"error":"Internal Server Error","requestId":"31f8f577/1-8"}at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:268)at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:249)at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:167)at service.HelloServiceGrpc$HelloServiceBlockingStub.hello(HelloServiceGrpc.java:160)at com.example.GrpcClient.main(GrpcClient.java:30)

报错信息解析,GrpcClient 报错结果来自于 Spring Cloud Gateway ,返回结果为不识别的返回内容 invalid content-type: application/json 这是由于 Spring Cloud Gateway 返回了的报错信息是 application/json 格式的,但是 GrpcClient 通过 grpc 协议通信,因此会将错误格式错误直接返回而非正确解析错误信息.

GrpcGateway 报错信息:

io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record: 00001204000000000000037fffffff000400100000000600002000000004080000000000000f0001at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1313) ~[netty-handler-4.1.100.Final.jar:4.1.100.Final]Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]*__checkpoint ⇢ HTTP POST "/HelloService/hello" [ExceptionHandlingWebHandler]
Original Stack Trace:at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1313) ~[netty-handler-4.1.100.Final.jar:4.1.100.Final]at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1383) ~[netty-handler-4.1.100.Final.jar:4.1.100.Final]

这里就是的报错信息是 GrpcGateway 无法正确解析来自 GrpcServer 的 http2 的包信息而产生的报错.这是由于 GrpcGateway 与 GrpcServer 在 h2c(Http2 Clean Text) 协议上的通信格式存在差异,从而引发报错.

最后是来自 GrpcServer 的报错:

628, 2024 9:18:03 下午 io.grpc.netty.shaded.io.grpc.netty.NettyServerTransport notifyTerminated
信息: Transport failed
io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception: HTTP/2 client preface string missing or corrupt. Hex dump for received bytes: 16030302650100026103036f6977c824c322105c600bd1dbat io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception.connectionError(Http2Exception.java:109)at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.readClientPrefaceString(Http2ConnectionHandler.java:321)at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.decode(Http2ConnectionHandler.java:247)at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:453)

这里就是 GrpcServer 与 GrpcGateway 通信过程由于协议包无法识别导致通信终止,从而引发报错.

报错场景2

在 Spring Cloud Gateway 的 application.yml 中同时配置了 use-insecure-trust-manager: truetrustedX509Certificates 导致的报错:

spring:cloud:gateway: #网关路由配置httpclient:ssl:use-insecure-trust-manager: truetrustedX509Certificates:- classpath:x509/ca.crt

use-insecure-trust-manager: true 表示在于 GrpcServer 通信的过程中不会验证服务器证书,这样如果证书存在什么问题的情况下就不会引发报错了,但是在同时配置了 use-insecure-trust-manager: truetrustedX509Certificates 的情况下 use-insecure-trust-manager: true 选项是不生效的,Spring Cloud Gateway 会还是尝试通过配置的 ca 证书去验证服务器证书,从而引发报错,因此不要同时配置 use-insecure-trust-manager: truetrustedX509Certificates这两个选项。

# 同时配置了 `use-insecure-trust-manager: true` 和 `trustedX509Certificates` 后服务证书校验失败报错
javax.net.ssl.SSLHandshakeException: No subject alternative names matching IP address 0:0:0:0:0:0:0:1 foundat java.base/sun.security.ssl.Alert.createSSLException(Alert.java:130) ~[na:na]Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]*__checkpoint ⇢ HTTP POST "/HelloService/hello" [ExceptionHandlingWebHandler]
Original Stack Trace:

客户端通常情况下只需要配置 ca 证书,用于验证服务器证书,但是验证服务器证书这一步是可以跳过的,在一些场景下服务器证书的校验比较严格的时候容易出问题,此时可以选择不进行服务器证书校验,在 Spring Cloud Gateway 代理访问 GrpcServer 时,可以为 Spring Cloud Gateway 配置 use-insecure-trust-manager: true 来取消对 GrpcServer 的强验证。

No subject alternative names matching IP address 0:0:0:0:0:0:0:1 found

这个问题就是在校验服务器证书时,由于服务器证书校验失败导致的报错了,通常情况下, client 会校验服务器的FQDN域名信息是否与请求的连接一致:

# 请求服务器证书
openssl req -new -nodes -sha256 -newkey rsa:2048 -keyout server.key -out server.csr \
-subj "/C=CN/ST=Zhejiang/L=Hangzhou/O=Ghimi Technology/OU=Ghimi Blog/CN=blog.ghimi.top"

上面是在使用命令生成服务器证书时配置的信息,其中 CN=blog.ghimi.top 就是我配置的域名信息,这就要求我的 GrpcServer 的 ip 地址绑定了这个域名,然后 GrpcClient 通过这个域名访问:

ManagedChannelBuilder<?> builder = Grpc.newChannelBuilder("blog.ghimi.top:7443", credentials);

在这种情况下 GrpcClient 会拿服务器返回的证书与当前连接信息进行比较,如果一致则服务器验证成功,否则验证失败并抛出异常.

在 GrpcServer 只有 ip 地址没有域名的情况下,基于域名的验证就不生效了,此时去做证书验证就一定会报错:

# 同时配置了 `use-insecure-trust-manager: true` 和 `trustedX509Certificates` 后服务证书校验失败报错
javax.net.ssl.SSLHandshakeException: No subject alternative names matching IP address 0:0:0:0:0:0:0:1 foundat java.base/sun.security.ssl.Alert.createSSLException(Alert.java:130) ~[na:na]Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]*__checkpoint ⇢ HTTP POST "/HelloService/hello" [ExceptionHandlingWebHandler]
Original Stack Trace:

报错信息中提到的 subject alternative names 就是在域名失效后的另外一种验证手段,他要求ca在签发服务器证书时向服务器证书中添加一段附加信息,这个信息中可以添加证书的可信 ip 地址:

# 通过 ca 证书颁发服务器证书
openssl x509 -req -in server.csr -out server.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -extensions SAN \
-extfile <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:dns.ghimi.top,IP:127.0.0.1"))

上面脚本中的 IP:127.0.0.1 就是添加的可信地址,我们可以同时添加多个服务器地址,以上面的报错为例,我们只需要在生成服务器证书的时候添加 ::1 的本地 ipv6 地址即可修复该错误:

openssl x509 -req -in server.csr -out server.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -extensions SAN \
-extfile <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:dns.ghimi.top,IP:127.0.0.1,IP:::1"))

报错场景4 使用 pkcs12 配置了多张自签名 ca 证书识别失效问题

解决方案,改为使用 Java Keystore 格式的证书即可修复.

参考资料

  • Spring Cloud Gateway and gRPC
  • spring-cloud-gateway-grpc
  • gRPC-Spring-Boot-Starter 文档
  • rx-java
  • Working with Certificates and SSL
  • 介绍一下 X.509 数字证书中的扩展项 subjectAltName

相关文章:

【笔记】Spring Cloud Gateway 实现 gRPC 代理

Spring Cloud Gateway 在 3.1.x 版本中增加了针对 gRPC 的网关代理功能支持,本片文章描述一下如何实现相关支持.本文主要基于 Spring Cloud Gateway 的 官方文档 进行一个实践练习。有兴趣的可以翻看官方文档。 由于 Grpc 是基于 HTTP2 协议进行传输的&#xff0c;因此 Srping …...

云顶之弈数据网站

摘要&#xff1a;随着云顶之弈游戏的广泛流行&#xff0c;玩家对于游戏数据的查询和最新资讯的获取需求呈现出显著增长的趋势。设计一款云顶之弈数据网站&#xff0c;为玩家提供便捷、高效的数据查询和资讯浏览服务&#xff0c;能满足玩家对于游戏数据的快速查询和实时资讯获取…...

Linux(Ubuntu)下源码开发整个流程完成版本(下载->编译->模拟器运行)

写这篇文章没别的意思, 年纪大了记性不好, 这次工作中下载,编译遇到了一些之前没遇到的问题,所以就所幸记录一下, 以便日后能快速查阅 好了, 正题开始 首先我们下载AOSP源代码开始 AOSP源代码下载 首先找到官网https://source.android.google.cn/ 进入后最上面点击获取源代…...

el-form表单实现校验

前端表单实现&#xff0c; rules 属性传入约定的验证规则&#xff0c;并将 form-Item 的 prop 属性设置为需要验证的特殊键值即可。 <el-form ref"ruleFormRef" :model"interviewForm" label-position"left" require-asterisk-position"…...

一台TrinityCore服务器客户端连接网速慢(未解决)

在FreeBSD开bhyve安装Ubuntu&#xff0c;然后安装了TrinityCore服务器&#xff0c;在只是经过一层NAT&#xff0c;两边都是局域网的情况下&#xff0c;连接速度竟然很慢&#xff0c;慢到600ms。 服务器安装见&#xff1a;尝试在FreeBSD 的jail、bhyve里安装TrinityCore-CSDN博…...

[系统运维|Xshell]宿主机无法连接上NAT网络下的虚拟机进行维护?主机ping不通NAT网络下的虚拟机,虚拟机ping的通主机!解决办法

遇到的问题&#xff1a;主机ping不通NAT网络下的虚拟机&#xff0c;虚拟机ping的通主机 服务器&#xff1a;Linux&#xff08;虚拟机&#xff09; 主机PC&#xff1a;Windows 虚拟机&#xff1a;vb&#xff0c;vm测试过没问题&#xff0c;vnc没测试不清楚 虚拟机网络&#xff1…...

C 语言实例 - 查找数组中最大的元素值

查找数组中最大的元素值。 实例 1 #include <stdio.h>int main() {int array[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};int loop, largest;largest array[0];for(loop 1; loop < 10; loop) {if( largest < array[loop] ) largest array[loop];}printf("最大…...

MySQL之可扩展性(七)

可扩展性 通过集群扩展 理想的扩展方案时单一逻辑数据库能够存储尽可能多的数据&#xff0c;处理尽可能多的查询&#xff0c;并如期望的那样增长。许多人的第一想法就是建立一个"集群"或者"网格"来无缝处理这些事情&#xff0c;这样应用就无须去做太多工…...

微服务框架中Nacos的个人学习心得

微服务框架需要学习的东西很多&#xff0c;基本上我把它分为了五个模块&#xff1a; 第一&#xff1a;微服务技术模块 分为三个常用小模块&#xff1a; 1.微服务治理&#xff1a; 注册发现 远程调用 配置管理 网关路由 2.微服务保护&#xff1a; 流量控制 系统保护 熔断降级 服…...

Unity Animator 运行时修改某个动画状态的播放速度

1.添加动画参数&#xff0c;选择需要动态修改速度的动画状态 2.在属性面板种设置速度倍速参数...

阿里云常用的操作

阿里云常见的产品和服务 容器服务 可以查看容器日志、监控容器cpu和内存&#xff0c; 日志服务 SLS 可以查看所有服务的日志&#xff0c; Web应用防火墙 WAF 可以查看 QPS. 阿里云查看集群&#xff1a; 点击 “产品和服务” 中的 容器服务&#xff0c;可以查看 集群列表&…...

【MATLAB源码-第231期】基于matlab的polar码编码译码仿真,对比SC,SCL,BP,SCAN,SSC等译码算法误码率。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 极化码&#xff08;Polar Code&#xff09; 极化码&#xff08;Polar Code&#xff09;是一种新型的信道编码技术&#xff0c;由土耳其裔教授Erdal Arıkan在2008年提出。极化码在理论上被证明能够在信道容量上达到香农极限…...

创新实训(十三) 项目开发——实现用户终止对话功能

思路分析&#xff1a; 如何实现用户终止AI正在进行的回答&#xff1f; 分析实现思路如下&#xff1a; 首先是在用户点击发送后&#xff0c;切换终止对话&#xff0c;点击后大模型终止对话&#xff0c;停止sse&#xff0c;不再接收后端的消息。同时因为对话记录存入数据库是后…...

基于Java+MySQL停车场车位管理系统详细设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;…...

LeetCode 53.最大子数组和(dp)

给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4] 输出&#xff1a;…...

IOS17闪退问题Assertion failure in void _UIGraphicsBeginImageContextWithOptions

最近项目更新到最新版本IOS17&#xff0c;发现一个以前的页面突然闪退了。原来是IOS17下&#xff0c;这个方法 UIGraphicsBeginImageContext(CGSize size) 已经被移除&#xff0c;原参数如果size为0的话&#xff0c;会出现闪退现象。 根据说明&#xff0c;上述方法已经被替换…...

float8格式

产生背景 在人工智能神经元网络中&#xff0c;一个参数用1字节表示即可&#xff0c;或者说&#xff0c;这是个猜想&#xff1a;因为图像的颜色用8比特表示就够了&#xff0c;所以说&#xff0c;猜想神经元的区分度应该小于256。 数字的分配 8比特有256个码位&#xff0c;分为…...

云效BizDevOps上手亲测

云效BizDevOps上手亲测 什么是云效项目协作Projex配置2023业务空间原始诉求字段原始诉求工作流创建原始诉求配置2023产品空间创建主题业务原始诉求关联主题配置2023研发空间新建需求需求关联主题 与传统区别云效开发流程传统开发流程云效BizDevOps 操作体验 什么是云效 在说到…...

亚太杯赛题思路发布(中文版)

导读&#xff1a; 本文将继续修炼回归模型算法&#xff0c;并总结了一些常用的除线性回归模型之外的模型&#xff0c;其中包括一些单模型及集成学习器。 保序回归、多项式回归、多输出回归、多输出K近邻回归、决策树回归、多输出决策树回归、AdaBoost回归、梯度提升决策树回归…...

【Linux】部署 GitLab 服务

1、配置实验环境 安装git apt install git 安装docker apt install docker 安装tree apt install tree 2、安装 Gitlab 下载官方库与安装包 下载官方库的安装脚本 curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bas…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...