0

I used one of one of the example of boost::beast web server asynchronous to communicate with client javascript using websocket. I am attempting to do the simple receiving image and write it in server side.

The result I receive in the server side is a broken jpg image. Thank you in advance.

client-side (javascript)

var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("image");

var ws = null;
connect.onclick = function() {
   ws = new WebSocket(uri.value);
   ws.onopen = function(ev) {
     messages.innerText += "[connection opened]\n";
   };
   ws.onclose = function(ev) {
     messages.innerText += "[connection closed]\n";
   };
   ws.onmessage = function(ev) {
     messages.innerText += ev.data + "\n";
   };
   ws.onerror = function(ev) {
     messages.innerText += "[error]\n";
     console.log(ev);
   };
 };
disconnect.onclick = function() {
   ws.close();
};
send.onclick = function() {
   var canvas1 = ctx.getImageData(0,0,img.width,img.height);
   var binary = new Uint8Array(img.data.length);
   for (var i=0; i<img.data.length; ++i) {
     binary[i] = img.data[i];
   }

   ws.send(binary.buffer);
}

server-side

void on_write(boost::system::error_code ec,
        std::size_t bytes_transferred)
{
   boost::ignore_unused(bytes_transferred);

   if(ec)
     return fail(ec, "write");

   buffer_.consume(buffer_.size());

   std::cout << "on write before do read\n";

   ws_.async_read(
            buffer_,
            boost::asio::bind_executor(
                strand_,
                std::bind(
                    &session::on_read,
                    shared_from_this(),
                    std::placeholders::_1,
                    std::placeholders::_2)));
   uint8_t *buf = new uint8_t [bytes_transferred];


boost::asio::buffer_copy(boost::asio::buffer(buf,bytes_transferred),buffer_.data(),bytes_transferred);
        ::cv::Mat mImg(400,320,CV_8UC3,buf);
        ::cv::imwrite("file.jpg",mImg);
      delete [] buf;

    }
  • `bytes_transferred` refers to the number of bytes written, not the number of bytes read. From looking at this code, it seems that you are not familiar with Asio's asynchronous interfaces. I suggest you take a step back and first learn Asio (a prerequisite for using Beast) and then this will make more sense. – Vinnie Falco Jun 12 '19 at 18:47

1 Answers1

0

I first recommend refactoring your code into small testable functions.

Write a function like this:

template <class AsyncStream, class CompletionToken>
auto
async_write_opencv_image(AsyncStream&, CompletionToken&& token)
{
  // write composed op here
}

Using this, you can feed in a boost::beast::test::stream to the function which will allow you to manually inspect the buffers to ensure the image's correctness.

This has the advantage that now your image writing code is stream-agnostic so you can swap it out for any other type.

If you need any assistance in this regard, there's ample documentation on boost.org as well as live-help on the cpplang slack team.

Edit:

Here's a wandbox example how to potentially also setup a unit test for websockets as well: https://wandbox.org/permlink/EixDmotCphJwiDZ1

ExBigBoss
  • 43
  • 6
  • Thank you. This is new for me. I didn't know there's an experimental version of boost beast. I will try this and modify as you suggested above. Is it like this example: https://www.boost.org/doc/libs/1_70_0/libs/beast/doc/html/beast/using_io/writing_composed_operations.html – Eric Jansen Jun 11 '19 at 01:01
  • I am having difficulties to separate the client and server from your example source code. How do I check if client can do "connect" to server? Thanks – Eric Jansen Jun 12 '19 at 05:58