gopath开发模式和go modules开发模式对比
goland创建项目时没用go mod模式选项的坑
在GoLand 2021.2 稳定版的更新文档里有一些对go modules的更新,欢迎界面的默认 Go 选项现在是 Go modules 项目的默认选项
解决warning: go env -w GOPROXY=... does not override conflicting OS environment variable问题
Go语言编码规范
什么是rpc?rpc开发的挑战是什么?
- Call ID映射:在本地调用中,函数体是直接通过函数指针来指定的,我们调用add,编译器就自动帮我们调用它相应的函数指针。但是在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。所以,在RPC中,所有的函数都必须有自己的一个ID。这个ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,必须附上这个ID。
- 序列化和反序列化。客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C++,客户端用Java或者Python)。这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。
- 网络传输。远程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把Call ID和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。
通过http完成简单的服务端的功能
客户端
1. 建立tcp/http连接
2, 将对象序列化成json字符串 -- 序列化
3. 发送json -- 调用成功后实际上你接收的是一个二级制的数据
4. 等待服务器发送结果
5. 将服务器返回的数据解析成对象 -- 反序列化
服务端
1. 监听端口
2. 读取数据 -- 二级制的json数据
3. 对数据进行反系列化对象
4. 开始处理业务逻辑
5. 将处理后的结果序列化为json二级制数据 -- 序列化
6. 将数据返回
反序列化和序列化是可以选择的,不一定采用json,xml,protobuf,msgpack
func main() {
//http://localhost:8000/add?a=1&b=2
http.HandleFunc("/add", func(w http.ResponseWriter, r *http.Request) {
//callID的问题,r.URL.PATH 数据传输协议 url的参数协议 网络传输协议http
_ = r.ParseForm()
fmt.Println("path: ", r.URL.Path)
a, _ := strconv.Atoi(r.Form["a"][0])
b, _ := strconv.Atoi(r.Form["b"][0])
w.Header().Set("Content-Type", "application/json")
data, _ := json.Marshal(map[string]int{
"data": a + b,
})
_, _ = w.Write(data)
})
_ = http.ListenAndServe("127.0.0.1:8000", nil)
}
import (
"encoding/json"
"fmt"
"github.com/kirinlabs/HttpRequest"
)
type ResponseDta struct {
Data int `json:"Data"`
}
func add(a, b int) int {
request := HttpRequest.NewRequest()
response, _ := request.Get(fmt.Sprintf("http://127.0.0.1:8000/%s?a=%d&b=%d", "add", a, b))
body, _ := response.Body()
fmt.Println(string(body))
responseDta := ResponseDta{}
_ = json.Unmarshal(body, &responseDta)
return responseDta.Data
}
func main() {
add(2, 2)
}
go 内置rpc
type HelloService struct {
}
func (s *HelloService) Hello(request string, reply *string) error {
*reply = "hell0 " + request
return nil
}
func main() {
// 1实例化一个server
listen, err := net.Listen("tcp", "127.0.0.1:1234")
// 2注册处理逻辑 handler
err = rpc.RegisterName("HelloService", &HelloService{})
// 3启动服务
accept, _ := listen.Accept()
rpc.ServeConn(accept)
}
func main() {
client, _ := rpc.Dial("tcp", "127.0.0.1:1234")
var reply string
err := client.Call("HelloService.Hello", "bobby", &reply)
if err != nil {
panic("")
}
fmt.Println(reply)
}
....优化代码:封装和解耦:略
protoc-gen-go 安装踩坑记录
--go_out: protoc-gen-go: plugins are not supported问题处理
protoc-gen-go: plugins are not supported问题处理
protobuf和json的对比
syntax = "proto3";
option go_package = "." ;
message HelloRequest {
string name = 1; // 1是编号
int32 age = 2;
repeated string course = 3;
}
protoc -I . helloworld.proto --go_out=plugins=grpc:.
package main
import (
"encoding/json"
"fmt"
"github.com/golang/protobuf/proto"
"rpcProject/DAY3/proto"
)
type Hello struct {
Name string `json:"name"`
Age string `json:"age"`
Courses []string `json:"courses"`
}
func main() {
request := __.HelloRequest{
Name: "Bobby",
Age: 18,
Course: []string{"go", "java", "scala"},
}
hello := Hello{
Name: "bobby",
Age: "18",
Courses: []string{"go", "java", "scala"},
}
protomarshal, _ := proto.Marshal(&request)
jsonmarshal, _ := json.Marshal(hello)
newrequest := __.HelloRequest{}
fmt.Println(len(protomarshal), len(jsonmarshal))
proto.Unmarshal(protomarshal, &newrequest)
fmt.Println(newrequest.Name, newrequest.Age, newrequest.Course)
}
为什么需要安装protoc和protoc-gen-go
解决 "google.golang.org/grpc" 报红
gopath路径grpc快速体验
syntax = "proto3";
option go_package = ".;proto";
service Greeter{
rpc SayHello(HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 2;
}
type Server struct {
}
func (s *Server) SayHello(ctx context.Context, re *proto.HelloRequest) (*proto.HelloReply, error) {
return &proto.HelloReply{
Message: "hello" + re.Name,
}, nil
}
func main() {
server := grpc.NewServer()
proto.RegisterGreeterServer(server, &Server{})
listen, _ := net.Listen("tcp", "0.0.0.0:8081")
_ = server.Serve(listen)
}
func main() {
conn, _ := grpc.Dial("0.0.0.0:8081", grpc.WithInsecure())
defer conn.Close()
client := proto.NewGreeterClient(conn)
reply, _ := client.SayHello(context.Background(), &proto.HelloRequest{
Name: "bobby",
})
fmt.Println(reply.Message)
}
grpc的流模式
option go_package的作用
用于生成的.pb.go文件,在引用时和生成go包名时起作用,前一个参数用于指定生成文件的位置,后一个参数指定生成的 .go 文件的 package
option go_package = "{out_path};out_go_package";
proto文件中import另一个proto文件
疑问:这怎么解决我这里可能没装插件,参考:protobuf中使用import需要注意的点
网友评论