c++jsonboostwebsocketbeast

Boost beast send json with byte array to client throw websocket


I have file which is converted from byte array to string

processResultJson.append(reinterpret_cast<const char *const>(im->bits), sizeof(im->bits));
processResultJson.append(reinterpret_cast<const char *const>(im->bits), im_res->bmi->bmiHeader.biSizeImage);

docData.put("Image1", processResultJson);}
boost::property_tree::json_parser::write_json(m_stream, SRegulaDR::docData);
resultString = m_stream.str();

size_t n = net::buffer_copy(buffer_.prepare(resultString.size()), net::buffer(resultString));        buffer_.commit(n);

in this situation i get error_code=2 - End of file and then error_code=995 I/O operation...

How i can send JSON with byte array witch converted to string Thanks!!!


Solution

  • Don't use Property Tree as if it's a JSON library. It has well known limitations: https://www.boost.org/doc/libs/1_75_0/doc/html/property_tree/parsers.html#property_tree.parsers.json_parser

    Note especially the limitationssurrounding arrays.

    Next up, you didn't write an array to begin with, instead writing a string. But since it's binary data, it may be a valid JSON string, and this could be a source of error.

    Also, you probably don't need to copy the whole JSON again to put it in a buffer. Instead, boost::asio::buffer(resultString) will work (as long as you make sure that the lifetime of resultString is enough, like with buffer_).

    Just testing a little does suggest that characters are being escaped correctly by write_json:

    Live On Compiler Explorer

    #define BOOST_BIND_GLOBAL_PLACEHOLDERS
    #include <boost/property_tree/json_parser.hpp>
    #include <iostream>
    using namespace std::string_literals;
    
    struct Im { std::array<std::uint64_t, 10> bits; };
    
    int main()
    {
        auto im = std::make_unique<Im>(
                Im { 0b0010'1100'1010'0010'0111'1100'0010 });
    
        std::string_view bitmsg(
            reinterpret_cast<char const*>(&im->bits),
            sizeof(im->bits));
    
        auto processResultJson = "some binary data: \0 \x10 \xef αβγδ\n"s;
        processResultJson += bitmsg;
    
        boost::property_tree::ptree docData; 
        docData.put("Image1", processResultJson);
        std::ostringstream oss;
        boost::property_tree::json_parser::write_json(oss, docData);
    
        std::cout << oss.str();
    }
    

    Prints

    { "Image1": "some binary data: \u0000 \u0010 αβγδ\nu0002\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" }

    Json lint reports it as valid JSON (for what it's worth)

    However, consider making doubly sure by

    Demo With Boost JSON

    1.75.0 introduced a proper JSON library. Let's celebrate.

    The straightforward translation is: https://godbolt.org/z/es9jGc

    json::object docData;
    docData["Image1"] = processResultJson;
    
    std::string resultString = json::serialize(docData);
    

    However, you can now easily use strong-typed, proper arrays: https://godbolt.org/z/K9c6bc

    json::object docData;
    docData["Image1"] = json::array(im->bits.begin(), im->bits.end());
    

    Printing

    {"Image1":[46802882,0,0,0,0,0,0,0,0,0]}
    

    Or you can, in fact, use default conversions with value_from: :

    Live On Compiler Explorer

    #include <iostream>
    #include <boost/json/src.hpp> // for header-only
    namespace json = boost::json;
    
    struct Im { std::array<std::uint64_t, 10> bits; };
    
    int main()
    {
        auto im = std::make_unique<Im>(
                Im { 0b0010'1100'1010'0010'0111'1100'0010, /*...*/ });
    
        std::cout << json::object{ {"Image1", json::value_from(im->bits) } };
    }
    

    Prints

    {"Image1":[46802882,0,0,0,0,0,0,0,0,0]}