3
\$\begingroup\$

I'm trying to retrieve a certain amount of data from a socket, both Unix domain and TCP, but I've no control over its format or length.

I discussed this with someone who told me to set my receiving buffer to a specific length, use async_read_some to read the first few bytes off the socket and then loop until the OS buffer is empty.

I decided to write the following code instead:

void read() noexcept {
      buffer_.resize(0);
      asio::async_read(*socket_, asio::buffer(buffer_), asio::transfer_all(),
                       [&](const std::error_code &ec, const size_t size) {
                         buffer_.resize(socket_->available());
                         asio::read(*socket_, asio::buffer(buffer_));
                         delegate_.on_read(ec, buffer_);
                       });
      service_.run();
      service_.reset();
    }

Is there anything obviously wrong with my method? Setting the buffer to 0 before calling the read method means the buffer will never be populated and calling a synchronous read() on the callback so async_read() means the blocking will take as long as it takes to copy data from the OS buffer to my local buffer.

Am I missing something else here?

Update:

The code for the socket:

struct Socket : public std::enable_shared_from_this<Socket> {
    explicit Socket(const std::string &socket) : endpoint_{socket} {
      socket_.reset(new asio::generic::stream_protocol::socket(service_));
      socket_->connect(endpoint_, delegate_.error_code);
      socket_->non_blocking(true);
      service_.run();
      service_.reset();
    }

    virtual ~Socket() noexcept = default;

    void write(const std::vector<uint8_t> &data) noexcept {
      asio::async_write(*socket_, asio::buffer(data),
                        [&](const std::error_code ec, const size_t length) {  });
      service_.run();
      service_.reset();
    }

    void read() noexcept {
      buffer_.resize(0);
      asio::async_read(*socket_, asio::buffer(buffer_), asio::transfer_all(),
                       [&](const std::error_code &ec, const size_t size) {
                         buffer_.resize(socket_->available());
                         asio::read(*socket_, asio::buffer(buffer_));
                       });
      service_.run();
      service_.reset();
    }

   private:
    asio::io_service service_;
    std::unique_ptr<asio::generic::stream_protocol::socket> socket_;
    asio::local::stream_protocol::endpoint endpoint_;

    std::string host_;
    std::string port_;
    std::vector<uint8_t> buffer_;
  };

But I was hoping to have someone with asio knowledge as I was told this could fail on specific scenarios like when the client sends more than 1GB of data.

\$\endgroup\$

closed as off-topic by Toby Speight, yuri, IEatBagels, Stephen Rauch, Mast Aug 22 '18 at 16:33

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Lacks concrete context: Code Review requires concrete code from a project, with sufficient context for reviewers to understand how that code is used. Pseudocode, stub code, hypothetical code, obfuscated code, and generic best practices are outside the scope of this site." – Toby Speight, yuri, IEatBagels, Stephen Rauch, Mast
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    \$\begingroup\$ Would you please make a minimal but complete example to be reviewed. Something I can just compile and test. \$\endgroup\$ – Maikel Aug 7 '17 at 9:37
  • 4
    \$\begingroup\$ @Maikel Good idea. To clarify, the usage example should come on top of the already posted code. Don't turn the posted code into example code. \$\endgroup\$ – Mast Aug 7 '17 at 9:44
  • 1
    \$\begingroup\$ You'll receive better reviews if you show a complete example. For example, I recommend that you show the necessary #include lines, and a main() that shows how to call your code. It's not mandatory, but it really helps! \$\endgroup\$ – Toby Speight Aug 7 '17 at 15:36