为什么gRPC服务器端在客户端完成流传输后卡住(客户端和服务器都在dart中编写)?

6ss1mwsb  于 2023-02-27  发布在  其他
关注(0)|答案(1)|浏览(501)

我想上传一个图像从客户端到服务器的gRPC。为此,我已经创建了下面的proto文件:

syntax = "proto3";

service EshopService {
    rpc UploadImage (stream ImageToUpload) returns (ImageLink);

}

message ImageToUpload {
    bytes image = 1;
}
message ImageLink {
    string image_links = 1;
}

在客户端为了流图像我写了下面的代码:

Future<ImageLink> uploadImage(ImageToUpload image) async {
    return await stub.uploadImage(streamImage(images.image));

  }

  Stream<ImageToUpload> streamImage(List<int> image) async* {
    for (var element in image) {
      yield ImageToUpload(image: [element]);
    }
  }

然后在服务器端我有下面的代码:

Future<ImageLink> uploadImage(grpc.ServiceCall call, Stream<ImageToUpload> request) async {
    print('uploading');
    final List<int> image = [];
    await for (var bytes in request) {
      image.addAll(bytes.image);
    }
    print('image gotten');
    File imageFile = File('image.jpg');
    await imageFile.writeAsBytes(image);
    return ImageLinks(imageLinks: 'image');
  }
}

图像被发送到服务器,并且正在被接收(我知道,因为我打印了它),但是服务器从来没有离开await for部分。它甚至在流完成后仍然停留在那里,并且在客户端,我在一段时间后得到以下错误

gRPC Error (code: 4, codeName: DEADLINE_EXCEEDED, message: Deadline exceeded, details: null, rawResponse: null, trailers: {})

我如何让服务器知道流已经完成,以便它退出for循环?

zphenhs4

zphenhs41#

我发现了这个问题。这是因为我一次发送一个字节,花费了太长时间,导致客户端超时。当我将每个流中的字节数改为128个字节时,这个问题得到了修复。因此,基本上我将客户端代码更改为:

Future<ImageLink> uploadImage(XFile image) async {
    return await stub.uploadImage(() async* {
      final imageBytes = await image.readAsBytes();
      int index = 0;
      while (index < imageBytes.length) {
        int lastIndex = index + 128;
        if (lastIndex > imageBytes.length) lastIndex = imageBytes.length;
        final data = ImageToUpload(
          image: imageBytes.sublist(index, lastIndex),
        );
        yield data;
        index = lastIndex;
      }
    }.call());
  }

相关问题