grpc-教程(golang版)

目录

一、介绍

二、环境准备

三、Golang中使用grpc

1.编写protobuf文件

2.服务端

3.客户端

四、proto文件详解

1.proto语法

2.数据类型 

基本数据类型

数组类型

map类型

嵌套类型

编写风格

3.多服务 

4.多个proto文件

五、流式传输

1.普通rpc

2.服务器流式

3.客户端流式 

4.双向流

六、配套代码


一、介绍

RPCRemote Procedure Call的简称,中文叫远程过程调用,简单的说,就是调用远程方法和调用本地方法一样

那么grpc就是由 google开发的一个高性能、通用的开源RPC框架

官网地址:Introduction to gRPC | gRPC

  1. gRPC是一种现代开源高性能远程过程调用(RPC)框架,可在任何环境中运行。
  2. 它可以高效地连接数据中心内的服务,并支持负载平衡、跟踪、健康检查和身份验证等插件功能。
  3. 它适用于分布式计算的最后一英里,以连接设备、移动应用程序和浏览器到后端服务。
  4. 公司已使用gRPC连接其环境中的多个服务,从连接少数服务到跨多种语言的数据中心内数百种服务。
  5. gRPC最初由谷歌创建,用于连接在其数据中心内和跨越其数据中心的大量微服务。

二、环境准备

以Golang使用为例,只需要在windows上安装protoc转换工具

官网地址:Go | gRPC

​# 下载网址:

https://github.com/protocolbuffers/protobuf/releases/download/v3.9.0/protoc-3.9.0-win64.zip

# go语言需要安装的依赖
go get github.com/golang/protobuf/proto
go get google.golang.org/grpc
go install github.com/golang/protobuf/protoc-gen-go

安装好之后,需要将protoc的bin目录添加到环境变量中

还需要将protoc-gen-go.exe的目录添加到环境变量中

刚刚添加之后,可能需要重启电脑或者重启goland,才能在goland的terminal中使用

三、Golang中使用grpc

整体结构如图:

1.编写protobuf文件

现在还没有学过怎么编写,不用担心,先复制粘贴就行了,主要是用于测试环境是否正常

创建文件夹 /grpc_proto 在该文件夹中创建文件 hello.proto ,编写内容如下:

syntax = "proto3"; // 指定proto版本
package hello_grpc;     // 指定默认包名

// 指定golang包名
option go_package = "/hello_grpc";

//定义rpc服务
service HelloService {
  // 定义函数
  rpc SayHello (HelloRequest) returns (HelloResponse) {}
}

// HelloRequest 请求内容
message HelloRequest {
  string name = 1;
  string message = 2;
}

// HelloResponse 响应内容
message HelloResponse{
  string name = 1;
  string message = 2;
}

在文件夹 /grpc_proto 中执行命令:protoc -I . --go_out=plugins=grpc:. .\hello.proto

或者编写set.bat批处理文件,方便使用,内容如下:

protoc -I . --go_out=plugins=grpc:.\grpc_proto .\grpc_proto\hello.proto

2.服务端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
	"net"
	"oslee/grpc_study/1base/grpc_proto/hello_grpc"
)

// HelloServer 得有一个结构体,需要实现这个服务的全部方法,叫什么名字不重要
type HelloServer struct {
}

func (HelloServer) SayHello(ctx context.Context, request *hello_grpc.HelloRequest) (*hello_grpc.HelloResponse, error) {
	fmt.Println("入参:", request.Name, request.Message)
	return &hello_grpc.HelloResponse{
		Name:    "server",
		Message: "hello " + request.Name,
	}, nil
}

func main() {
	// 监听端口
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		grpclog.Fatalf("Failed to listen: %v", err)
	}

	// 创建一个gRPC服务器实例。
	s := grpc.NewServer()
	server := HelloServer{}
	// 将server结构体注册为gRPC服务。
	hello_grpc.RegisterHelloServiceServer(s, &server)
	fmt.Println("grpc server running :8080")
	// 开始处理客户端请求。
	err = s.Serve(listen)
}

3.客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
	"oslee/grpc_study/1base/grpc_proto/hello_grpc"
)

func main() {
	addr := ":8080"
	// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。
	// 此处使用不安全的证书来实现 SSL/TLS 连接
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))
	}
	defer conn.Close()
	// 初始化客户端
	client := hello_grpc.NewHelloServiceClient(conn)
	result, err := client.SayHello(context.Background(), &hello_grpc.HelloRequest{
		Name:    "client",
		Message: "hello",
	})
	fmt.Println(result, err)
}

调用结果如下:

四、proto文件详解

1.proto语法

  • service 对应的就是go里面的接口,可以作为服务端,客户端
  • rpc 对应的就是结构体中的方法
  • message对应的也是结构体

2.数据类型 

基本数据类型

message Request {
  double a1 = 1;
  float a2 = 2;
  int32 a3 = 3;
  uint32 a4 = 4;
  uint64 a5 = 5;
  sint32 a6 = 6;
  sint64 a7 = 7;
  fixed32 a8 = 8;
  fixed64 a9 = 9;
  sfixed32 a10 = 10;
  sfixed64 a11 = 11;
  bool a12 = 12;
  string a13 = 13;
  bytes a14 = 14;
}

对应go类型

type Request struct {
  state         protoimpl.MessageState
  sizeCache     protoimpl.SizeCache
  unknownFields protoimpl.UnknownFields

  A1  float64 `protobuf:"fixed64,1,opt,name=a1,proto3" json:"a1,omitempty"`
  A2  float32 `protobuf:"fixed32,2,opt,name=a2,proto3" json:"a2,omitempty"`
  A3  int32   `protobuf:"varint,3,opt,name=a3,proto3" json:"a3,omitempty"`
  A4  uint32  `protobuf:"varint,4,opt,name=a4,proto3" json:"a4,omitempty"`
  A5  uint64  `protobuf:"varint,5,opt,name=a5,proto3" json:"a5,omitempty"`
  A6  int32   `protobuf:"zigzag32,6,opt,name=a6,proto3" json:"a6,omitempty"`
  A7  int64   `protobuf:"zigzag64,7,opt,name=a7,proto3" json:"a7,omitempty"`
  A8  uint32  `protobuf:"fixed32,8,opt,name=a8,proto3" json:"a8,omitempty"`
  A9  uint64  `protobuf:"fixed64,9,opt,name=a9,proto3" json:"a9,omitempty"`
  A10 int32   `protobuf:"fixed32,10,opt,name=a10,proto3" json:"a10,omitempty"`
  A11 int64   `protobuf:"fixed64,11,opt,name=a11,proto3" json:"a11,omitempty"`
  A12 bool    `protobuf:"varint,12,opt,name=a12,proto3" json:"a12,omitempty"`
  A13 string  `protobuf:"bytes,13,opt,name=a13,proto3" json:"a13,omitempty"`
  A14 []byte  `protobuf:"bytes,14,opt,name=a14,proto3" json:"a14,omitempty"`
}

标量类型

.proto Type解释Go Type
doublefloat64
floatfloat32
int32使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代int32
uint32使用变长编码uint32
uint64使用变长编码uint64
sint32使用变长编码,这些编码在负值时比int32高效的多int32
sint64使用变长编码,有符号的整型值。编码时比通常的int64高效int64
fixed32总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。uint32
fixed64总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。uint64
sfixed32总是4个字节int32
sfixed64总是8个字节int64
boolbool
string一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本string
bytes可能包含任意顺序的字节数据[]byte

标量类型如果没有被赋值,则不会被序列化,解析时,会赋予默认值

  • strings:空字符串
  • bytes:空序列
  • bools:false
  • 数值类型:0

数组类型

message ArrayRequest {
  repeated int64 a1 = 1;
  repeated string a2 = 2;
  repeated Request request_list = 3;
}

对应go类型 

type ArrayRequest struct {
  A1          []int64 
  A2          []string   
  RequestList []*Request
}

map类型

键只能是基本类型

message MapRequest {
  map<int64, string> m_i_s = 1;
  map<string, bool> m_i_b = 2;
  map<string, ArrayRequest> m_i_arr = 3;
}

对应go类型 

type MapRequest struct {

  MIS   map[int64]string
  MIB   map[string]bool
  MIArr map[string]*ArrayRequest
}

嵌套类型

message Q1 {
  message Q2{
    string name2 = 2;
  }
  string name1 = 1;
  Q2 q2 = 2;
}

对应go类型

type Q1 struct {
  state         protoimpl.MessageState
  sizeCache     protoimpl.SizeCache
  unknownFields protoimpl.UnknownFields
  Name1 string `protobuf:"bytes,1,opt,name=name1,proto3" json:"name1,omitempty"`
  Q2    *Q1_Q2 `protobuf:"bytes,2,opt,name=q2,proto3" json:"q2,omitempty"`
}

个人习惯不嵌套,分开写

编写风格

  • 文件名建议下划线,例如:my_student.proto
  • 包名和目录名对应
  • 服务名、方法名、消息名均为大驼峰
  • 字段名为下划线

3.多服务 

proto文件

syntax = "proto3"; // 指定proto版本
// 指定golang包名
option go_package = "/duo_server";

service VideoService {
  rpc Look(Request)returns(Response){}
}

service OrderService {
  rpc Buy(Request)returns(Response){}
}

message Request{
  string name = 1;
}
message Response{
  string name = 1;
}

服务端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"log"
	"net"
	"oslee/grpc_study/2duo_server/grpc_proto/duo_server"
)

type VideoServer struct {
}

func (VideoServer) Look(ctx context.Context, request *duo_server.Request) (res *duo_server.Response, err error) {
	fmt.Println("video:", request)
	return &duo_server.Response{
		Name: "server",
	}, nil
}

type OrderServer struct {
}

func (OrderServer) Buy(ctx context.Context, request *duo_server.Request) (res *duo_server.Response, err error) {
	fmt.Println("order:", request)
	return &duo_server.Response{
		Name: "server",
	}, nil
}

func main() {
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	s := grpc.NewServer()
	duo_server.RegisterVideoServiceServer(s, &VideoServer{})
	duo_server.RegisterOrderServiceServer(s, &OrderServer{})
	fmt.Println("grpc server程序运行在:8080")
	err = s.Serve(listen)
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
	"oslee/grpc_study/2duo_server/grpc_proto/duo_server"
)

func main() {
	addr := ":8080"
	// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。
	// 此处使用不安全的证书来实现 SSL/TLS 连接
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))
	}
	defer conn.Close()

	orderClient := duo_server.NewOrderServiceClient(conn)
	res, err := orderClient.Buy(context.Background(), &duo_server.Request{
		Name: "client",
	})
	fmt.Println(res, err)

	videoClient := duo_server.NewVideoServiceClient(conn)
	res, err = videoClient.Look(context.Background(), &duo_server.Request{
		Name: "client",
	})
	fmt.Println(res, err)

}

4.多个proto文件

当项目大起来之后,会有很多个service,rpc,message

我们会将不同服务放在不同的proto文件中,还可以放一些公共的proto文件

本质就是生成go文件,需要在一个包内

proto文件 

common.proto

syntax = "proto3";
package proto;
option go_package = "/proto";


message Request{
  string name = 1;
}
message Response{
  string name = 1;
}

order.proto

syntax = "proto3";
package proto;
option go_package = "/proto";
import "common.proto";

service OrderService {
  rpc Look(Request)returns(Response){}
}

video.proto

syntax = "proto3";
package proto;
option go_package = "/proto";
import "common.proto";

service VideoService {
  rpc Look(Request)returns(Response){}
}

服务端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"log"
	"net"
	"oslee/grpc_study/3duo_proto/grpc_proto/proto"
)

type VideoServer struct {
}

func (VideoServer) Look(ctx context.Context, request *proto.Request) (res *proto.Response, err error) {
	fmt.Println("video:", request)
	return &proto.Response{
		Name: "server",
	}, nil
}

type OrderServer struct {
}

func (OrderServer) Look(ctx context.Context, request *proto.Request) (res *proto.Response, err error) {
	fmt.Println("order:", request)
	return &proto.Response{
		Name: "server",
	}, nil
}

func main() {
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	s := grpc.NewServer()
	proto.RegisterVideoServiceServer(s, &VideoServer{})
	proto.RegisterOrderServiceServer(s, &OrderServer{})
	fmt.Println("grpc server程序运行在:8080")
	err = s.Serve(listen)
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
	"oslee/grpc_study/3duo_proto/grpc_proto/proto"
)

func main() {
	addr := ":8080"
	// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。
	// 此处使用不安全的证书来实现 SSL/TLS 连接
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))
	}
	defer conn.Close()

	orderClient := proto.NewOrderServiceClient(conn)
	res, err := orderClient.Look(context.Background(), &proto.Request{
		Name: "client",
	})
	fmt.Println(res, err)

	videoClient := proto.NewVideoServiceClient(conn)
	res, err = videoClient.Look(context.Background(), &proto.Request{
		Name: "client",
	})
	fmt.Println(res, err)
}

五、流式传输

1.普通rpc

一问一答式,文章前面已讲

2.服务器流式

建立连接后,不知道服务端什么时候发送完毕,使用场景:下载文件 

 proto文件

syntax = "proto3";
option go_package = "/proto";

message Request {
  string name = 1;
}

message FileResponse{
  string file_name = 1;
  bytes content = 2;
}
service ServiceStream{
  rpc DownLoadFile(Request)returns(stream FileResponse){}
}

服务端

package main

import (
	"fmt"
	"google.golang.org/grpc"
	"io"
	"log"
	"net"
	"os"
	"oslee/grpc_study/4download/grpc_proto/proto"
)

type ServiceStream struct{}

func (ServiceStream) DownLoadFile(request *proto.Request, stream proto.ServiceStream_DownLoadFileServer) error {
	fmt.Println(request)
	file, err := os.Open("F:\\yckj\\workspace_gitee\\1own\\os_lee\\go_grpc_study\\res\\protoc-3.9.0-win64.zip")
	if err != nil {
		return err
	}
	defer file.Close()

	for {
		buf := make([]byte, 2048)
		_, err = file.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			break
		}
		stream.Send(&proto.FileResponse{
			Content: buf,
		})
	}
	return nil
}

func main() {
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	server := grpc.NewServer()
	proto.RegisterServiceStreamServer(server, &ServiceStream{})

	server.Serve(listen)
}

 客户端

package main

import (
	"bufio"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"io"
	"log"
	"os"
	"oslee/grpc_study/4download/grpc_proto/proto"
)

func main() {
	addr := ":8080"
	// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。
	// 此处使用不安全的证书来实现 SSL/TLS 连接
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))
	}
	defer conn.Close()
	// 初始化客户端
	client := proto.NewServiceStreamClient(conn)

	stream, err := client.DownLoadFile(context.Background(), &proto.Request{
		Name: "张三",
	})

	file, err := os.OpenFile("F:\\yckj\\workspace_gitee\\1own\\os_lee\\go_grpc_study\\res\\protoc-3.9.0-win64_down.zip", os.O_CREATE|os.O_WRONLY, 0600)
	if err != nil {
		log.Fatalln(err)
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	var index int
	for {
		index++
		response, err := stream.Recv()
		if err == io.EOF {
			break
		}
		fmt.Printf("第%d 次, 写入 %d 数据\n", index, len(response.Content))
		writer.Write(response.Content)
	}
	writer.Flush()
}

3.客户端流式 

建立连接后,不知道客户端什么时候发送完毕,使用场景:上传文件

proto文件

syntax = "proto3";
option go_package = "/proto";
message Response {
  string Text = 1;
}
message FileRequest{
  string file_name = 1;
  bytes content = 2;
}
service ClientStream{
  rpc UploadFile(stream FileRequest)returns(Response){}
}

服务端

package main

import (
	"bufio"
	"fmt"
	"google.golang.org/grpc"
	"io"
	"log"
	"net"
	"os"
	"oslee/grpc_study/5upload/grpc_proto/proto"
)

type ClientStream struct{}

func (ClientStream) UploadFile(stream proto.ClientStream_UploadFileServer) error {

	file, err := os.OpenFile("F:\\yckj\\workspace_gitee\\1own\\os_lee\\go_grpc_study\\res\\protoc-3.9.0-win64_up.zip", os.O_CREATE|os.O_WRONLY, 0600)
	if err != nil {
		log.Fatalln(err)
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	var index int
	for {
		index++
		response, err := stream.Recv()
		if err == io.EOF {
			break
		}
		writer.Write(response.Content)
		fmt.Printf("第%d次", index)
	}
	writer.Flush()
	stream.SendAndClose(&proto.Response{Text: "完毕了"})
	return nil
}

func main() {
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	server := grpc.NewServer()
	proto.RegisterClientStreamServer(server, &ClientStream{})

	server.Serve(listen)
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"io"
	"log"
	"os"
	"oslee/grpc_study/5upload/grpc_proto/proto"
)

func main() {
	addr := ":8080"
	// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。
	// 此处使用不安全的证书来实现 SSL/TLS 连接
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))
	}
	defer conn.Close()
	// 初始化客户端
	client := proto.NewClientStreamClient(conn)
	stream, err := client.UploadFile(context.Background())

	file, err := os.Open("F:\\yckj\\workspace_gitee\\1own\\os_lee\\go_grpc_study\\res\\protoc-3.9.0-win64.zip")
	if err != nil {
		log.Fatalln(err)
	}
	defer file.Close()

	for {
		buf := make([]byte, 2048)
		_, err = file.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			break
		}
		stream.Send(&proto.FileRequest{
			FileName: "x.png",
			Content:  buf,
		})
	}
	response, err := stream.CloseAndRecv()
	fmt.Println(response, err)
}

4.双向流

使用场景:聊天室

proto文件

syntax = "proto3";
option go_package = "/proto";

message Request {
  string name = 1;
}
message Response {
  string Text = 1;
}

service BothStream{
  rpc Chat(stream Request)returns(stream Response){}
}

服务端

package main

import (
	"fmt"
	"google.golang.org/grpc"
	"log"
	"net"
	"oslee/grpc_study/6chat/grpc_proto/proto"
)

type BothStream struct{}

func (BothStream) Chat(stream proto.BothStream_ChatServer) error {
	for i := 0; i < 10; i++ {
		request, _ := stream.Recv()
		fmt.Println(request)
		stream.Send(&proto.Response{
			Text: "你好",
		})
	}
	return nil
}

func main() {
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	server := grpc.NewServer()
	proto.RegisterBothStreamServer(server, &BothStream{})

	server.Serve(listen)
}

客户端 

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
	"oslee/grpc_study/6chat/grpc_proto/proto"
)

func main() {
	addr := ":8080"
	// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。
	// 此处使用不安全的证书来实现 SSL/TLS 连接
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))
	}
	defer conn.Close()
	// 初始化客户端
	client := proto.NewBothStreamClient(conn)
	stream, err := client.Chat(context.Background())

	for i := 0; i < 10; i++ {
		stream.Send(&proto.Request{
			Name: fmt.Sprintf("第%d次", i),
		})
		response, err := stream.Recv()
		fmt.Println(response, err)
	}
}

六、配套代码

代码下载地址:

go_grpc_study: Golang使用grpc教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/531932.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从零开始学习的ai教程视频,如何入手?

个人认为小白想零基础学习ai应该从理论和实操两个方面入手。理论是支撑实践的前提&#xff0c;只有以一种全局观角度了解ai才能实现从熟练使用ai到有自我意识的用ai创作。 接下来将会简单介绍一些理论免费学习网站和软件&#xff08;一笔带过&#xff0c;不重点&#xff09;&a…

构造析构理解与拷贝函数初识

1. 6个默认成员函数 ----初始化和清理{ 1.构造 2.析构 } -----拷贝复制{ 1.拷贝构造 2.赋值重载 } ------取地址重载{ 1.普通对象 2.const对象取地址 } 注&#xff1a;构造函数的目的是初始…

【Vue】生命周期

生命周期钩子(lifecycle-hooks) 每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤&#xff0c;比如设置好数据侦听&#xff0c;编译模板&#xff0c;挂载实例到 DOM&#xff0c;以及在数据改变时更新 DOM。在此过程中&#xff0c;它也会运行被称为生命周期钩子的函数&a…

鸿蒙实战开发-如何实现查看系统相册、最近删除、收藏夹操作功能

介绍 本示例主要展示了相册相关的功能&#xff0c;使用ohos.file.photoAccessHelper 接口&#xff0c;实现了查看系统相册、创建用户相册、查看相册照片、用户相册文件添加和删除、以及预览图片、最近删除、收藏夹操作等功能; 效果预览 使用说明 主界面&#xff1a;查询显示…

【基于PSINS工具箱】组合导航,EKF与UKF的对比,使用153模型

代码简述 【务必注意】 需要事先安装PSINS工具箱!!! 如果没有工具箱,网上面很多,实在找不到可以找我要链接。没有工具箱是无法直接运行本程序的。 程序根据153的模型(15维状态量、3维GNSS观测量),在自己定义了一个运动路径后,使用EKF和UKF对状态进行估计,并绘制轨迹…

PostgreSQL入门到实战-第十四弹

PostgreSQL入门到实战 PostgreSQL数据过滤(七)官网地址PostgreSQL概述PostgreSQL中BETWEEN 命令理论PostgreSQL中BETWEEN 命令实战更新计划 PostgreSQL数据过滤(七) BETWEEN运算符允许您检查值是否在值的范围内。 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容…

OpenHarmony应用编译 - 如何在源码中编译复杂应用(4.0-Release)

文档环境 开发环境&#xff1a;Windows 11 编译环境&#xff1a;Ubuntu 22.04 开发板型号&#xff1a;DAYU 200&#xff08;RK3568&#xff09; 系统版本&#xff1a;OpenHarmony-4.0-Release 功能简介 在 OpenHarmony 系统中预安装应用的 hap 包会随系统编译打包到镜像中&a…

element用户上传头像组件带大图预览,和删除功能

element 用户上传组件不支持大图预览&#xff0c;拿组件的简单修改一些&#xff0c;发表上来主要是记一下&#xff0c;以后可以用 效果图 <template><div class"flex-img"><div class"el-upload-list el-upload-list--picture-card" v-sh…

论文笔记:The Reversal Curse: LLMs trained on “A is B” fail to learn “B is A”

iclr 2024 reviewer 评分668 1 intro 论文揭示了自回归大模型&#xff08;LLM&#xff09;中令人惊讶的泛化失败【反转诅咒】 如果模型在“A is B”形式的句子上进行训练&#xff0c;它不会自动泛化到相反的方向“B is A”通过对“Uriah Hawthorne 是深渊旋律的作曲家”等虚构…

微服务项目sc2024父工程

1.基础版本要求 jdk 17maven 3.9mysql 8.0spring boot 3.2.0spring cloud 2023.0.0spring cloud alibaba 2022.0.0.0-RC2 2.创建父工程 2.1.字符编码 2.2.java编译版本 2.3.注解生效激活 2.4.File Type过滤 2.5.父工程中只保留pom文件,其余的删了 3.父工程pom文件 <?xm…

Covalent Network(CQT)推出以太坊质押迁移计划,以增强长期结构化数据可用性、塑造万亿级 LLM 参数体系

作为 Web3 领先的链上数据层&#xff0c;Covalent Network&#xff08;CQT&#xff09;宣布了其将质押操作从 Moonbeam 迁移回以太坊的决定。此举是 Covalent Network&#xff08;CQT&#xff09;走向以太坊时光机&#xff08;EWM&#xff09;的第一步&#xff0c;EWM 是一个为…

TensorFlow学习之:深度学习基础

神经网络基础 神经网络是深度学习的核心&#xff0c;它们受人脑的结构和功能启发&#xff0c;能够通过学习大量数据来识别模式和解决复杂问题。神经网络的基本工作原理包括前向传播和反向传播两个阶段。 前向传播&#xff08;Forward Propagation&#xff09; 前向传播是神经…

OpenC910 datasheet 2.0 翻译

概述 C910是由THEAD半导体有限公司开发的一款RISC-V兼容的64位高性能处理器。它通过架构和微架构创新&#xff0c;在控制流、计算和频率方面提供行业领先的性能。C910处理器基于RV64GC指令集&#xff0c;并实现了XIE&#xff08;XuanTie指令扩展&#xff09;技术。C910采用先进…

友思特应用 | 高精度呈现:PCB多类型缺陷检测系统

导读 PCB等电子产品的精密生产制造过程中&#xff0c;往往需要将缺陷问题100%高精度暴露。友思特 PCB 多类型缺陷检测系统&#xff0c;借由Neuro-T深度学习模型自动排查全部微小缺陷&#xff0c;为工业 PCB 生产制造提供了先进可靠的质量保障。 在现代制造业中&#xff0c;尤其…

TLF9471 - High-Speed CAN FD Transceiver

1 框图描述 2 功能描述 CAN收发器被设计用来承受汽车应用的恶劣条件&#xff0c;并支持12V应用。   SBC的控制器区域网络&#xff08;CAN&#xff09;收发器部分在汽车和工业应用中提供高速&#xff08;HS&#xff09;差分模式数据传输&#xff08;最高可达2Mbaud&#xff09…

kali使用msf+apkhook520+cploar实现安卓手的攻击

学习网络安全的过程中&#xff0c;突发奇想怎么才能控制或者说是攻击手机 边找工作边实验 话不多说启动kali 一、使用msfapktool生成简单的木马程序 首先使用kali自带的msfvenom写上这样一段代码 选择安卓 kali的ip 一个空闲的端口 要输出的文件名 msfvenom -p android/met…

【软件测试】个人博客系统测试

个人博客系统测试 一、项目背景1.1 技术背景1.2 功能背景 二、自动化测试2.1 什么是自动化测试2.2 通过使用selenium进行自动化测试的编写&#xff08;Java实现&#xff09;2.3 编写测试用例&#xff0c;执行自动化测试2.3.1 输入用户名:test,密码:123&#xff0c;登录成功2.3.…

深度学习图像处理04:图像分类模型训练实战——动物分类

这篇博文不涉及理论知识&#xff0c;主要通过一个完整的深度学习模型训练流程&#xff0c;直观地了解深度学习图像分类任务。有关理论的部分&#xff0c;之前几篇博文已经涉及基础部分&#xff0c;之后也会对一些理论进行补充。 本文将结合代码&#xff0c;主要介绍三部分内容…

halcon缺陷检测-印刷品检测(差异化模型),键盘字符缺陷检测

前言 在实际项目中&#xff0c;印刷品缺陷检测是缺陷检测中的难点项目。通常印刷品检测往往具备缺陷小&#xff0c;缺陷所在位置不固定&#xff0c;出现少印或者多印的情况。并且由于产线原因&#xff0c;大量的印刷品在视野中的大小并不是完全一致的&#xff0c;可能出现细微…