【问题标题】:How to identify a disconnected client in gRPC?如何在 gRPC 中识别断开连接的客户端?
【发布时间】:2019-09-20 19:23:59
【问题描述】:

我正在使用 gRPC 构建一个 API,在服务器端,我希望在客户端断开连接时收到通知,识别它并基于此执行一些任务。

到目前为止,我能够使用grpc.StatsHandler 方法HandleConn 检测到客户端断开连接。我尝试使用上下文传递值,但无法从服务器端访问它们。

客户端:

conn, err := grpc.DialContext(
    context.WithValue(context.Background(), "user_id", 1234),
    address,
    grpc.WithInsecure(),
)

服务器端:

// Build stats handler
type serverStats struct {}

func (h *serverStats) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
    return ctx
}

func (h *serverStats) HandleRPC(ctx context.Context, s stats.RPCStats) {}

func (h *serverStats) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
    return context.TODO()
}

func (h *serverStats) HandleConn(ctx context.Context, s stats.ConnStats) {
    fmt.Println(ctx.Value("user_id")) // Returns nil, can't access the value

    switch s.(type) {
    case *stats.ConnEnd:
        fmt.Println("client disconnected")
        break
    }
}


// Build server
s := grpc.NewServer(grpc.StatsHandler(&serverStats{}))

我想在服务器端访问从客户端传递的值。正确的做法是什么,或者有没有其他方法可以识别已断开连接的客户端?

【问题讨论】:

  • I tried passing values using context 我不确定具体细节,但如果您使用 GRPC 元数据可能会出现这种情况:(github.com/grpc/grpc-go/blob/master/Documentation/…),但我不确定 GRPC 方法调用的顺序以及何时/如何/何处在 nGRPC 协议中发送元数据(即它是否总是在HandleConn 中可用?你的用例是什么?通过使操作幂等(或可能的其他方法)来处理断开连接可能有替代方法。

标签: go grpc grpc-go


【解决方案1】:

我认为您在拨号时可能不会传递该值,但您可以标记连接,然后所有下一个客户端请求在其上下文中将具有相同的值:

在你的 serverStats 实现中:

func (h *serverStats) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
    return context.WithValue(ctx, "user_counter", userCounter++)
}

在您的服务实现中

func (s *service) SetUserId(ctx context.Context, v MyMessage) (r MyResponse, err Error) {

   s.userIdMap[ctx.Value("user_counter")] = v.userId
...

}

在其他方法中:


func (s *service) AnotherMethod(ctx context.Context, v MyMessage) (r MyResponse, err Error) {

   userId := s.userIdMap[ctx.Value("user_counter")]
...

}
func (h *serverStats) HandleConn(ctx context.Context, s stats.ConnStats) {

    switch s.(type) {
    case *stats.ConnEnd:
        fmt.Printf("client %d disconnected", s.userIdMap[ctx.Value("user_counter")])
        break
    }
}

如果您找到在拨号步骤中传递值的方法,请告诉我。

【讨论】:

    【解决方案2】:

    我尝试使用上下文传递值,但无法从服务器端访问它们。

    您需要将元数据字段显式设置为客户端上下文:

    ctx := context.Background()
    ctx = metadata.AppendToOutgoingContext(ctx, "user_id", "1234")
    conn, err := grpc.DialContext(cxt, address)
    

    在服务器端,您可以像这样检索它们:

    md, ok := metadata.FromIncomingContext(ctx)
    

    正确的做法是什么,或者有没有其他方法可以识别已断开连接的客户端?

    这实际上取决于您的用例。我认为 GRPC Stats API 适用于一些简单的任务(例如,计算延迟或聚合网络统计信息),但是当客户端离开时某些业务逻辑应该工作时,它并不是很有用。为此,我建议直接在 GRPC 处理程序中使用 defer 调用。另一种选择是实现自定义 GRPC 拦截器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      • 1970-01-01
      相关资源
      最近更新 更多