1

I want to upload an image from client to server in gRPC. For this purpose i have created the proto file below:

syntax = "proto3";

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

}

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

in client in order to stream the image i have written the code below:

 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]);
    }
  }

then on server side I have the code below:

 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');
  }
}

the image is sent to the server and it is being received (I know because I printed it out), but the server never gets out of the await for section. It gets stuck there even after the stream is complete and on client side I get the following error after a while

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

how do I let the server know that the stream is completed so it will get out of the for loop?

Kimiya Zargari
  • 324
  • 1
  • 14
  • I'm unfamiliar with Dart but I think you're misunderstanding the use of gRPC streaming. Streaming involves sending one or more messages. In your case, one or more `ImageToUpload` messages. Your implementation does **not** stream the bytes of `image`. See the Protobuf site for an [example](https://grpc.io/docs/languages/dart/basics/) using Dart that includes client- and server-side streaming – DazWilkin Feb 25 '23 at 19:57
  • It's unclear what images you're shipping with gRPC, gRPC can be unsuitable for shipping [large messages](https://protobuf.dev/programming-guides/techniques/#large-data). An alternative is to use a mechanism better suited to BLOB transfer, get some URL for the result and then include the URL in a message from your client informing the server of the BLOB's location. – DazWilkin Feb 25 '23 at 20:00
  • @DazWilkin Thank you for the response. I actually foud the protocol buffer code for sending the image from stackoverflow; however, I found the issue. It was because I was sending one byte at a time and that took too long, which resulted in a timeout at the client side. It got fixed when I changed it to 128 bytes in each stream. I'm gonna add my answer, I would appreciate it if you took a look at my answer. – Kimiya Zargari Feb 26 '23 at 07:20

1 Answers1

0

I found the issue. It was because I was sending one byte at a time and that took too long, which resulted in a timeout at the client side. It got fixed when I changed it to 128 bytes in each stream. So basically I changed the client side code to this:

 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());
  }
Kimiya Zargari
  • 324
  • 1
  • 14