go 不一样的grpc入门示例

发布于 2022-10-30 17:19:52阅读 1157

之所以说不一样,是因为在这里你看不到.proto文件,当然也无需生成任何代码

之所以这么神奇是我用了buf,它托管了我的.proto文件,并且自动生成了相关代码,详情请移步:https://www.cuiwei.net/p/1679512807

服务端极简示例

下面的示例提供了一个AdminLogin服务

server.go

package main

import (
	"context"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
	"google.golang.org/grpc"
	"net"
)

type blogService struct {
	*blogv1.UnimplementedBlogServiceServer
}

func (s *blogService) AdminLogin(ctx context.Context, in *blogv1.AdminLoginRequest) (*blogv1.AdminLoginResponse, error) {
	return &blogv1.AdminLoginResponse{
		Id:       1,
		Username: "aa",
		Token:    "xx",
	}, nil
}

func main() {
	lis, _ := net.Listen("tcp", ":9087")
	gRPCServer := grpc.NewServer()
	blogv1.RegisterBlogServiceServer(gRPCServer, &blogService{})
	gRPCServer.Serve(lis)
}

客户端极简示例

下面的客户端示例也可以说是一个测试用例,执行TestBlogServerLogin方法可以验证AdminLogin服务的可用性

server_test.go

package main

import (
	"context"
	"fmt"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"testing"
)

var conn *grpc.ClientConn
var client blogv1.BlogServiceClient

func init() {
	//conn, err = grpc.Dial(":9087", grpc.WithInsecure()) //过时的
	conn, _ = grpc.Dial(":9087", grpc.WithTransportCredentials(insecure.NewCredentials()))
	client = blogv1.NewBlogServiceClient(conn)
}

func TestBlogServiceLogin(t *testing.T) {
	resp, err := client.AdminLogin(context.Background(), &blogv1.AdminLoginRequest{
		Username: "admin22",
		Password: "123",
	})
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(resp)
}

目录结构

如上,服务端和客户端都是一个文件,实际项目中肯定不这样。如何拆分呢,这对新手来说可能是个问题。我这里抛砖引玉,下面只说服务端

将上文的server.go改名为main.go,并把里面的&blogService{}移出去,移到两个目录,分别是servicesapi目录。services/BlogService.go定义了全部的服务,具体实现在api目录

将上文的server_test.go移到为services/blog_service_test.go

最终等到的目录结构如下

.
├── README.md
├── api
│   ├── admin.go
│   └── article.go
├── go.mod
├── go.sum
├── main.go
└── services
    ├── BlogService.go
    └── blog_service_test.go

最后是关键文件的代码

main.go

package main

import (
	"demo/grpc/services"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
	"google.golang.org/grpc"
	"net"
)

func main() {
	lis, _ := net.Listen("tcp", ":9087")
	gRPCServer := grpc.NewServer()
	blogv1.RegisterBlogServiceServer(gRPCServer, services.BlogService)
	gRPCServer.Serve(lis)
}

services/BlogService.go

package services

import (
	"context"
	"demo/grpc/api"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
)

var BlogService = &blogService{}

//func NewBlogService() *blogService {
//	return &blogService{}
//}

type blogService struct {
	*blogv1.UnimplementedBlogServiceServer //解决"missing mustEmbedUnimplementedBlogServiceServer method"的问题
}

//func (s *blogService) mustEmbedUnimplementedBlogServiceServer() {
//	//为了解决"missing mustEmbedUnimplementedBlogServiceServer method"的问题,但我测试时不好使
//}

func (s *blogService) AdminLogin(ctx context.Context, in *blogv1.AdminLoginRequest) (*blogv1.AdminLoginResponse, error) {
	return api.AdminLogin(ctx, in)
}

//这里只定义一个管理员的,其他的,像文章也都可以定义到这里,最终在api目录的实现再分开

api/admin.go

package api

import (
	"context"
	blogv1 "go.buf.build/grpc/go/cuiwei/blog/admin/v1"
)

func AdminLogin(ctx context.Context, in *blogv1.AdminLoginRequest) (*blogv1.AdminLoginResponse, error) {
	return &blogv1.AdminLoginResponse{
		Id:       1,
		Username: "aa",
		Token:    "xx",
	}, nil
}

看,是不是清晰多了~

广而告之,我的新作品《语音助手》上架Google Play了,欢迎下载体验