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{}
移出去,移到两个目录,分别是services
,api
目录。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
}
看,是不是清晰多了~