Golang gRPC中遇到undefined: RegisterChatServiceServer错误如何解决

Golang gRPC中遇到undefined: RegisterChatServiceServer错误如何解决 尝试使用Go构建我的第一个gRPC应用,步骤如下:

1.1. 安装所需的Go库

PS D:\grpc> go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
PS D:\grpc> go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

1.2. 将GOPATH/bin添加到PATH环境变量中,以便命令行能够识别protoc-gen-goprotoc-gen-grpc命令。

2.1. 从以下地址为Windows下载protoc二进制文件https://github.com/protocolbuffers/protobuf/releases/

2.2. 解压protoc压缩文件,并将其bin文件夹添加到PATH环境变量中。

3.1. 编写proto文件如下:

// file: grpc/chat/chat.proto
syntax = "proto3";
package chat;
option go_package = "github.com/hajsf/grpc/chat";

message MessageRequest {
  string body = 1;
}

message MessageResponse {
    string body = 1;
  }

service ChatService {
  rpc SayHello(MessageRequest) returns (MessageResponse) {}
}

3.3. 编译proto文件以从grpc文件夹生成chat.pb.go

PS D:\grpc> protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative chat.proto

相应地生成了两个文件:chat.pb.gochat_grpc.pb.go

3.4. 添加chat.go文件如下:

// file: grpc/chat/chat.go
package main

import (
	"log"

	chat "github.com/hajsf/grpc/chat"
	"golang.org/x/net/context"
)

type Server struct {
}

func (s *Server) SayHello(ctx context.Context, in *chat.MessageRequest) (*chat.MessageResponse, error) {
	log.Printf("Receive message body from client: %s", in.Body)
	return &chat.MessageResponse{Body: "Hello From the Server!"}, nil
}
  1. 构建服务器文件如下:
// file: grpc/server/main.go
package main

import (
	"fmt"
	"log"
	"net"

	"github.com/hajsf/grpc/chat"
	"google.golang.org/grpc"
)

func main() {

	fmt.Println("Go gRPC Beginners Tutorial!")

	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 9000))
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}

	s := chat.Server{}

	grpcServer := grpc.NewServer()

	chat.RegisterChatServiceServer(grpcServer, &s)

	if err := grpcServer.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %s", err)
	}
}
  1. 构建客户端文件如下:
// file: grpc/client/main.go
package main

import (
	"log"

	"golang.org/x/net/context"
	"google.golang.org/grpc"

	"github.com/hajsf/grpc/chat"
)

func main() {

	var conn *grpc.ClientConn
	conn, err := grpc.Dial(":9000", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %s", err)
	}
	defer conn.Close()

	c := chat.NewChatServiceClient(conn) // 为什么找不到?

	response, err := c.SayHello(context.Background(), &chat.MessageRequest{Body: "Hello From Client!"})
	if err != nil {
		log.Fatalf("Error when calling SayHello: %s", err)
	}
	log.Printf("Response from server: %s", response.Body)

}
  1. 在上述提到的三个文件夹chatserverclient中,分别创建了GO模块,命令如下:
PS D:\grpc> go mod init github.com/hajsf/grpc/<filenale>
PS D:\grpc> go mod tidy
  1. 尝试运行server,但遇到以下错误:
PS D:\grpc\server> go run github.com/hajsf/grpc/server
# github.com/hajsf/grpc/server
.\main.go:21:12: undefined: chat.Server
.\main.go:25:7: undefined: chat.RegisterChatServiceServer
  1. 尝试运行client,但遇到以下错误:
PS D:\grpc\client> go run github.com/hajsf/grpc/client
# github.com/hajsf/grpc/client
.\main.go:21:12: undefined: chat.NewChatServiceClient

代码已加载到GitHub仓库:hajsf/grpc (github.com)


更多关于Golang gRPC中遇到undefined: RegisterChatServiceServer错误如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang gRPC中遇到undefined: RegisterChatServiceServer错误如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个错误是因为你的项目结构导致了包导入路径问题。你为每个目录单独创建了Go模块,但gRPC生成的代码期望在同一个模块中。

问题分析:

  1. chat目录是一个独立的Go模块
  2. serverclient目录也是独立的Go模块
  3. 生成的chat_grpc.pb.go文件中的RegisterChatServiceServerNewChatServiceClient函数在chat模块中
  4. serverclient模块无法正确访问这些函数

解决方案:

方法1:使用单一模块(推荐)

删除所有子目录的go.mod文件,只在根目录创建一个模块:

# 在D:\grpc目录下
PS D:\grpc> del chat\go.mod
PS D:\grpc> del server\go.mod
PS D:\grpc> del client\go.mod
PS D:\grpc> go mod init github.com/hajsf/grpc
PS D:\grpc> go mod tidy

然后更新你的文件结构:

// server/main.go 保持不变,但确保导入路径正确
package main

import (
    "fmt"
    "log"
    "net"

    "github.com/hajsf/grpc/chat"  // 现在指向正确的包
    "google.golang.org/grpc"
)

func main() {
    fmt.Println("Go gRPC Beginners Tutorial!")

    lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 9000))
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    s := &chat.Server{}  // 注意:这里应该是你实现的Server类型

    grpcServer := grpc.NewServer()
    chat.RegisterChatServiceServer(grpcServer, s)

    if err := grpcServer.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %s", err)
    }
}

方法2:如果你需要保持多模块结构,修改chat.go

// chat/chat.go 需要修改
package chat  // 改为chat包,而不是main

import (
    "log"
    "golang.org/x/net/context"
)

// 确保这个结构体实现了生成的接口
type Server struct {
    chat.UnimplementedChatServiceServer  // 嵌入这个以向前兼容
}

func (s *Server) SayHello(ctx context.Context, in *MessageRequest) (*MessageResponse, error) {
    log.Printf("Receive message body from client: %s", in.Body)
    return &MessageResponse{Body: "Hello From the Server!"}, nil
}

然后在server中正确导入:

// server/main.go
package main

import (
    "fmt"
    "log"
    "net"

    "github.com/hajsf/grpc/chat"
    "google.golang.org/grpc"
)

func main() {
    fmt.Println("Go gRPC Beginners Tutorial!")

    lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 9000))
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    s := &chat.Server{}
    grpcServer := grpc.NewServer()
    
    // 现在这个函数应该可以找到了
    chat.RegisterChatServiceServer(grpcServer, s)

    if err := grpcServer.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %s", err)
    }
}

方法3:检查protoc生成的文件

确保protoc命令正确生成了所有必要的代码。检查chat_grpc.pb.go文件是否包含:

// 应该有这样的函数
func RegisterChatServiceServer(s grpc.ServiceRegistrar, srv ChatServiceServer) {
    s.RegisterService(&ChatService_ServiceDesc, srv)
}

// 和这样的函数
func NewChatServiceClient(cc grpc.ClientConnInterface) ChatServiceClient {
    return &chatServiceClient{cc}
}

重新生成protobuf文件:

PS D:\grpc> protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative chat/chat.proto

确保生成的.pb.go文件在正确的目录中,并且所有模块都能正确访问它们。

回到顶部