[Boost-users] asio::transfer_at_least strange behavior

116 views
Skip to first unread message

Timenkov Yuri

unread,
Feb 12, 2009, 1:01:59 PM2/12/09
to boost...@lists.boost.org, Christopher M. Kohlhoff
Hi
Is transfer_at_least supposed to return success only if requested number of bytes transferred at once or at all?

For example, I want to receive 800 bytes and put them into streambuf using transfer_at_least(800) as completion condition, but I receive 2 chunks of 400 bytes, therefore I never get a success, because transfer_at_least_t always wants more data.

I know, there are may be some problems with handler copying, but the name of function is misleading, and may be should be documented.

I'm using boost 1.37, may be something has changed in 1.38.

Igor R

unread,
Feb 12, 2009, 2:16:47 PM2/12/09
to boost...@lists.boost.org
Is transfer_at_least supposed to return success only if requested number of bytes transferred at once or at all?

http://www.boost.org/doc/libs/1_37_0/doc/html/boost_asio/reference/transfer_at_least.html
"Return a completion condition function object that indicates that a read or write operation *should continue until* a minimum number of bytes has been transferred, or until an error occurs."

 
For example, I want to receive 800 bytes and put them into streambuf using transfer_at_least(800) as completion condition, but I receive 2 chunks of 400 bytes, therefore I never get a success, because transfer_at_least_t always wants more data.

When 800 bytes are received (at once or by chunks) or error occurs, the completion handler is invoked - that's the effect of this completion condition. If you encounter different behaviour, could you please provide minimal code demonstrating this?

Timenkov Yuri

unread,
Feb 12, 2009, 3:14:59 PM2/12/09
to boost...@lists.boost.org
Yes, exactly. Code snippet may be uselese, but I'm using something like this:
boost::asio::read(sock, buf, boost::asio::transfer_at_least(800), myhandler);

and myhandler is never called (because no more data arrives).

From implementation:
class transfer_at_least_t
{
public:
  typedef std::size_t result_type;

  explicit transfer_at_least_t(std::size_t minimum)
    : minimum_(minimum)
  {
  }

  template <typename Error>
  std::size_t operator()(const Error& err, std::size_t bytes_transferred)
  {
    return (!!err || bytes_transferred >= minimum_)
    ? 0 : default_max_transfer_size;
  }

private:
  std::size_t minimum_;
};

This handler called after each read operation and bytes_transferred each time is 400, but minimum_ is 800.


_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Igor R

unread,
Feb 12, 2009, 4:22:58 PM2/12/09
to boost...@lists.boost.org
Yes, exactly. Code snippet may be uselese, but I'm using something like this:
boost::asio::read(sock, buf, boost::asio::transfer_at_least(800), myhandler);

and myhandler is never called (because no more data arrives).


So, probably 800 bytes do not arrive, or there's some other issue.

 
This handler called after each read operation and bytes_transferred each time is 400, but minimum_ is 800.

Look at the implementation of read():
(Note that bytes_transferred passed to the completion_condition is accumulated each time)

template <typename SyncReadStream, typename MutableBufferSequence,
    typename CompletionCondition>
std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
    CompletionCondition completion_condition, boost::system::error_code& ec)
{
  ec = boost::system::error_code();
  boost::asio::detail::consuming_buffers<
    mutable_buffer, MutableBufferSequence> tmp(buffers);
  std::size_t total_transferred = 0;
  tmp.set_max_size(detail::adapt_completion_condition_result(
        completion_condition(ec, total_transferred)));
  while (tmp.begin() != tmp.end())
  {
    std::size_t bytes_transferred = s.read_some(tmp, ec);
    tmp.consume(bytes_transferred);
    total_transferred += bytes_transferred;
    tmp.set_max_size(detail::adapt_completion_condition_result(
          completion_condition(ec, total_transferred)));
  }
  return total_transferred;
}



Timenkov Yuri

unread,
Feb 13, 2009, 4:24:20 AM2/13/09
to boost...@lists.boost.org
Yes, my bad, sorry for noise.

Actually, I've used streambuf to read HTTP response with content-length. But some data was already in buffer. I've changed my code to something like this:
contentLength -= boost::asio::buffer_size(m_readBuffer.data());
boost::asio::async_read(m_socket, m_readBuffer, boost::asio::transfer_at_least(contentLength),
                myhandler);

And now everything works fine.
Thanks for help.
Reply all
Reply to author
Forward
0 new messages