Golang grpc:如何确定服务器何时开始侦听?

Golang grpc:如何确定服务器何时开始侦听?,go,concurrency,grpc,Go,Concurrency,Grpc,因此,我有以下几点: type Node struct { Table map[string]string thing.UnimplementedGreeterServer address string } func (n *Node) Start() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to

因此,我有以下几点:

type Node struct {
    Table map[string]string
    thing.UnimplementedGreeterServer
    address string
}




func (n *Node) Start() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    s := grpc.NewServer()
    thing.RegisterGreeterServer(s, n)
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}
在我的主要功能中,我将旋转多个节点,如下所示:

func main() {
    n :=Node{Table: map[string]string{}}
    go n.Start()
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())

}
问题是,由于我同时旋转节点,拨号连接可能无法工作,因为节点可能尚未设置

理想情况下,我希望有一个
done
频道,告诉我grpc服务器何时实际开始监听。我如何做到这一点

这与没有答案的问题本质上是相同的。Serve(listener)块,因此您无法通过完成chan来实现您的目的,相反,您必须实现和准备好您的服务,并在执行客户端的任何请求之前检查这些。 服务器应实现以下协议:

syntax = "proto3";

package grpc.health.v1;

message HealthCheckRequest {
  string service = 1;
}

message HealthCheckResponse {
  enum ServingStatus {
    UNKNOWN = 0;
    SERVING = 1;
    NOT_SERVING = 2;
    SERVICE_UNKNOWN = 3;  // Used only by the Watch method.
  }
  ServingStatus status = 1;
}

service Health {
  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);

  rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
例如,可以使用上面的proto


请阅读以了解更多信息。

只要net.Listen返回零错误,就可以拨打服务器。拨号将被阻止,直到服务器呼叫为止(在这种情况下,这将发生在s.Serve的某个地方)

将侦听器的创建移动到调用方并将其作为参数传递:

func (n *Node) Start(lis net.Listener) {
    s := grpc.NewServer()
    thing.RegisterGreeterServer(s, n)
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    n := Node{Table: map[string]string{}}
    go n.Start(lis)
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
}
或在侦听器返回后发出侦听器已启动的信号:

func (n *Node) Start(up chan struct{}) {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    if up != nil {
        close(up)
    }

    s := grpc.NewServer()
    thing.RegisterGreeterServer(s, n)
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

func main() {
    n := Node{Table: map[string]string{}}

    up := make(chan struct{})
    go n.Start(up)
    <-up

    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
}
func(n*节点)启动(启动chan结构{}){
lis,err:=net.Listen(“tcp”,端口)
如果错误!=零{
log.Fatalf(“未能侦听:%v”,错误)
}
如果上升!=零{
特写
}
s:=grpc.NewServer()
注册服务器(s,n)
如果错误:=s.Serve(lis);错误!=nil{
log.Fatalf(“未能送达:%v”,错误)
}
}
func main(){
n:=节点{表:映射[字符串]字符串{}
up:=make(chan结构{})
启动

简单的解决方案,没有第三方,倾听/接受之间没有间隙,没有随机超时

func main(){
n:=节点{表:映射[字符串]字符串{}
开始,开始
conn,err:=grpc.Dial(“本地主机:50051”,grpc.WithUnsecure(),grpc.WithBlock())
如果错误!=零{
对于i:=0;i<10;i++{
conn,err=grpc.Dial(“localhost:50051”,grpc.withunsecure(),grpc.WithBlock())

Start
将永远阻塞,或返回错误,因此,您无法获得通知它已成功启动的信号。您只能获得通知它失败的信号。最简单的方法是使用某个阈值重试拨号以退出。如果net.Listen返回零错误,服务器将开始侦听。您可以随后发送信号或通过将侦听器作为参数启动。实际上,如果tcp侦听没有错误,它可以启动得非常快。您可以进行延迟,例如在grpc之前进行time.Sleep(time.Second)。对于@Peter提到的点,Dial()是不正确的。service()将阻止,直到停止侦听。@HaiTH,没有任何东西可以阻止开始关闭某些信号通道或调用net.Listen和srv.Serve之间的任何东西。@Peter因为tcp在grpc实际工作之前仍然存在差距。grpc协议中的这些接口是吗?你说的更一般吗?@nz_21是的,我更新了答案,以提供r参考链接。这个健康检查协议在某种程度上是标准的,像Envegate这样的负载平衡器可以使用它。这是一个很好的答案。我想知道
listen()
accept()
之间的延迟是否足够重要,以至于它使通道信号没有看上去那么有用。