Added buffering implementation for send operations.
This commit is contained in:
parent
40e376e4b4
commit
8a3d80d22c
@ -18,10 +18,12 @@
|
|||||||
#include "asio/detail/push_options.hpp"
|
#include "asio/detail/push_options.hpp"
|
||||||
|
|
||||||
#include "asio/detail/push_options.hpp"
|
#include "asio/detail/push_options.hpp"
|
||||||
|
#include <cstring>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include <boost/type_traits.hpp>
|
#include <boost/type_traits.hpp>
|
||||||
#include "asio/detail/pop_options.hpp"
|
#include "asio/detail/pop_options.hpp"
|
||||||
|
|
||||||
|
#include "asio/send.hpp"
|
||||||
#include "asio/fixed_buffer.hpp"
|
#include "asio/fixed_buffer.hpp"
|
||||||
|
|
||||||
namespace asio {
|
namespace asio {
|
||||||
@ -36,7 +38,8 @@ public:
|
|||||||
/// Construct, passing the specified argument to initialise the next layer.
|
/// Construct, passing the specified argument to initialise the next layer.
|
||||||
template <typename Arg>
|
template <typename Arg>
|
||||||
explicit buffered_send_stream(Arg& a)
|
explicit buffered_send_stream(Arg& a)
|
||||||
: next_layer_(a)
|
: next_layer_(a),
|
||||||
|
buffer_()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,17 +70,92 @@ public:
|
|||||||
return next_layer_.demuxer();
|
return next_layer_.demuxer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The buffer type for this buffering layer.
|
||||||
|
typedef Buffer buffer_type;
|
||||||
|
|
||||||
|
/// Get the recv buffer used by this buffering layer.
|
||||||
|
buffer_type& recv_buffer()
|
||||||
|
{
|
||||||
|
return buffer_;
|
||||||
|
}
|
||||||
|
|
||||||
/// Close the stream.
|
/// Close the stream.
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
next_layer_.close();
|
next_layer_.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Flush all data from the buffer to the next layer. Returns the number of
|
||||||
|
/// bytes wrriten to the next layer on the last send operation, or 0 if the
|
||||||
|
/// underlying connection was closed. Throws an exception on failure.
|
||||||
|
size_t flush()
|
||||||
|
{
|
||||||
|
size_t total_bytes_sent = 0;
|
||||||
|
size_t last_bytes_sent = send_n(next_layer_, buffer_.begin(),
|
||||||
|
buffer_.size(), &total_bytes_sent);
|
||||||
|
buffer_.pop(total_bytes_sent);
|
||||||
|
return last_bytes_sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flush all data from the buffer to the next layer. Returns the number of
|
||||||
|
/// bytes wrriten to the next layer on the last send operation, or 0 if the
|
||||||
|
/// underlying connection was closed.
|
||||||
|
template <typename Error_Handler>
|
||||||
|
size_t flush(Error_Handler error_handler)
|
||||||
|
{
|
||||||
|
size_t total_bytes_sent = 0;
|
||||||
|
size_t last_bytes_sent = send_n(next_layer_, buffer_.begin(),
|
||||||
|
buffer_.size(), &total_bytes_sent, error_handler);
|
||||||
|
buffer_.pop(total_bytes_sent);
|
||||||
|
return last_bytes_sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Handler>
|
||||||
|
class flush_handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
flush_handler(Buffer& buffer, Handler handler)
|
||||||
|
: buffer_(buffer),
|
||||||
|
handler_(handler)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Error>
|
||||||
|
void operator()(const Error& e, size_t total_bytes_sent,
|
||||||
|
size_t last_bytes_sent)
|
||||||
|
{
|
||||||
|
buffer_.pop(total_bytes_sent);
|
||||||
|
handler_(e, last_bytes_sent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Buffer& buffer_;
|
||||||
|
Handler handler_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Start an asynchronous flush.
|
||||||
|
template <typename Handler>
|
||||||
|
void async_flush(Handler handler)
|
||||||
|
{
|
||||||
|
async_send_n(next_layer_, buffer_.begin(), buffer_.size(),
|
||||||
|
flush_handler<Handler>(buffer_, handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start an asynchronous flush.
|
||||||
|
template <typename Handler, typename Completion_Context>
|
||||||
|
void async_flush(Handler handler, Completion_Context context)
|
||||||
|
{
|
||||||
|
async_send_n(next_layer_, buffer_.begin(), buffer_.size(),
|
||||||
|
flush_handler<Handler>(buffer_, handler), context);
|
||||||
|
}
|
||||||
|
|
||||||
/// Send the given data to the peer. Returns the number of bytes sent or 0 if
|
/// Send the given data to the peer. Returns the number of bytes sent or 0 if
|
||||||
/// the stream was closed cleanly. Throws an exception on failure.
|
/// the stream was closed cleanly. Throws an exception on failure.
|
||||||
size_t send(const void* data, size_t length)
|
size_t send(const void* data, size_t length)
|
||||||
{
|
{
|
||||||
return next_layer_.send(data, length);
|
if (buffer_.size() == buffer_.capacity() && !flush())
|
||||||
|
return 0;
|
||||||
|
return copy(data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send the given data to the peer. Returns the number of bytes sent or 0 if
|
/// Send the given data to the peer. Returns the number of bytes sent or 0 if
|
||||||
@ -85,15 +163,65 @@ public:
|
|||||||
template <typename Error_Handler>
|
template <typename Error_Handler>
|
||||||
size_t send(const void* data, size_t length, Error_Handler error_handler)
|
size_t send(const void* data, size_t length, Error_Handler error_handler)
|
||||||
{
|
{
|
||||||
return next_layer_.send(data, length, error_handler);
|
if (buffer_.size() == buffer_.capacity() && !flush(error_handler))
|
||||||
|
return 0;
|
||||||
|
return copy(data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Handler>
|
||||||
|
class send_handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
send_handler(Buffer& buffer, const void* data, size_t length,
|
||||||
|
Handler handler)
|
||||||
|
: buffer_(buffer),
|
||||||
|
data_(data),
|
||||||
|
length_(length),
|
||||||
|
handler_(handler)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Error>
|
||||||
|
void operator()(const Error& e, size_t bytes_sent)
|
||||||
|
{
|
||||||
|
if (e || bytes_sent == 0)
|
||||||
|
{
|
||||||
|
handler_(e, bytes_sent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using namespace std; // For memcpy.
|
||||||
|
size_t orig_size = buffer_.size();
|
||||||
|
size_t bytes_avail = buffer_.capacity() - orig_size;
|
||||||
|
size_t bytes_copied = (length_ < bytes_avail) ? length_ : bytes_avail;
|
||||||
|
buffer_.resize(orig_size + bytes_copied);
|
||||||
|
memcpy(buffer_.begin() + orig_size, data_, bytes_copied);
|
||||||
|
handler_(e, bytes_copied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Buffer& buffer_;
|
||||||
|
const void* data_;
|
||||||
|
size_t length_;
|
||||||
|
Handler handler_;
|
||||||
|
};
|
||||||
|
|
||||||
/// Start an asynchronous send. The data being sent must be valid for the
|
/// Start an asynchronous send. The data being sent must be valid for the
|
||||||
/// lifetime of the asynchronous operation.
|
/// lifetime of the asynchronous operation.
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
void async_send(const void* data, size_t length, Handler handler)
|
void async_send(const void* data, size_t length, Handler handler)
|
||||||
{
|
{
|
||||||
next_layer_.async_send(data, length, handler);
|
if (buffer_.size() == buffer_.capacity())
|
||||||
|
{
|
||||||
|
async_flush(send_handler<Handler>(buffer_, data, length, handler));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t bytes_copied = copy(data, length);
|
||||||
|
next_layer_.demuxer().operation_immediate(
|
||||||
|
detail::bind_handler(handler, 0, bytes_copied));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start an asynchronous send. The data being sent must be valid for the
|
/// Start an asynchronous send. The data being sent must be valid for the
|
||||||
@ -102,7 +230,17 @@ public:
|
|||||||
void async_send(const void* data, size_t length, Handler handler,
|
void async_send(const void* data, size_t length, Handler handler,
|
||||||
Completion_Context context)
|
Completion_Context context)
|
||||||
{
|
{
|
||||||
next_layer_.async_send(data, length, handler, context);
|
if (buffer_.size() == buffer_.capacity())
|
||||||
|
{
|
||||||
|
async_flush(send_handler<Handler>(buffer_, data, length, handler),
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t bytes_copied = copy(data, length);
|
||||||
|
next_layer_.demuxer().operation_immediate(
|
||||||
|
detail::bind_handler(handler, 0, bytes_copied), context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receive some data from the peer. Returns the number of bytes received or
|
/// Receive some data from the peer. Returns the number of bytes received or
|
||||||
@ -138,8 +276,26 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Copy data into the internal buffer from the specified source buffer.
|
||||||
|
/// Returns the number of bytes copied.
|
||||||
|
size_t copy(const void* data, size_t length)
|
||||||
|
{
|
||||||
|
using namespace std; // For memcpy.
|
||||||
|
|
||||||
|
size_t orig_size = buffer_.size();
|
||||||
|
size_t bytes_avail = buffer_.capacity() - orig_size;
|
||||||
|
size_t bytes_copied = (length < bytes_avail) ? length : bytes_avail;
|
||||||
|
buffer_.resize(orig_size + bytes_copied);
|
||||||
|
memcpy(buffer_.begin() + orig_size, data, bytes_copied);
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
/// The next layer.
|
/// The next layer.
|
||||||
Next_Layer next_layer_;
|
Next_Layer next_layer_;
|
||||||
|
|
||||||
|
// The data in the buffer.
|
||||||
|
Buffer buffer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asio
|
} // namespace asio
|
||||||
|
@ -83,6 +83,37 @@ public:
|
|||||||
stream_impl_.close();
|
stream_impl_.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Flush all data from the buffer to the next layer. Returns the number of
|
||||||
|
/// bytes wrriten to the next layer on the last send operation, or 0 if the
|
||||||
|
/// underlying connection was closed. Throws an exception on failure.
|
||||||
|
size_t flush()
|
||||||
|
{
|
||||||
|
return stream_impl_.next_layer().flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flush all data from the buffer to the next layer. Returns the number of
|
||||||
|
/// bytes wrriten to the next layer on the last send operation, or 0 if the
|
||||||
|
/// underlying connection was closed.
|
||||||
|
template <typename Error_Handler>
|
||||||
|
size_t flush(Error_Handler error_handler)
|
||||||
|
{
|
||||||
|
return stream_impl_.next_layer().flush(error_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start an asynchronous flush.
|
||||||
|
template <typename Handler>
|
||||||
|
void async_flush(Handler handler)
|
||||||
|
{
|
||||||
|
return stream_impl_.next_layer().async_flush(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start an asynchronous flush.
|
||||||
|
template <typename Handler, typename Completion_Context>
|
||||||
|
void async_flush(Handler handler, Completion_Context context)
|
||||||
|
{
|
||||||
|
return stream_impl_.next_layer().async_flush(handler, context);
|
||||||
|
}
|
||||||
|
|
||||||
/// Send the given data to the peer. Returns the number of bytes sent or 0 if
|
/// Send the given data to the peer. Returns the number of bytes sent or 0 if
|
||||||
/// the stream was closed cleanly. Throws an exception on failure.
|
/// the stream was closed cleanly. Throws an exception on failure.
|
||||||
size_t send(const void* data, size_t length)
|
size_t send(const void* data, size_t length)
|
||||||
|
Loading…
Reference in New Issue
Block a user