Re: [Boost-bugs] [Boost C++ Libraries] #7837: Datagram packing of UDP BufferSequences

Subject: Re: [Boost-bugs] [Boost C++ Libraries] #7837: Datagram packing of UDP BufferSequences
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2012-12-29 19:39:54


#7837: Datagram packing of UDP BufferSequences
-----------------------------------------+----------------------------------
  Reporter: rafael_gago_81@… | Owner: chris_kohlhoff
      Type: Feature Requests | Status: new
 Milestone: To Be Determined | Component: asio
   Version: Boost 1.52.0 | Severity: Showstopper
Resolution: | Keywords: udp; asio; scatter-gatther
-----------------------------------------+----------------------------------

Comment (by anonymous):

 Hello!

 First of all to congratulate you for the great library design.

 I'm finding a limitation that makes boost asio udp use impractical.

 I'm writing an UDP based simple transfer protocol in a context where I
 want to avoid TCP latency (excessive ACK's between endpoints with high
 RTT), rate limitings and congestion control mechanisms. I also want to be
 able to set the datagram size (directly or indirectly, in my side of
 course) to minimize the bit error rate and collissions when doing wireless
 transmissions.

 I do transfer big data sizes (files/video/whatever) in fixed size chunks
 to control the UDP datagram size. Doing this requires that each chunk has
 a header with its transaction, chunk number, etc.

 What I'm doing now is allocating/storing the chunk headers storage/data
 and passing ConstBufferSequence containing a pair of buffers (chunk header
 + data chunk) to the "async_write_to" member function. I manage the chunk
 headers. The data buffer in the sequence belongs to external buffers, so I
 can avoid copying using the scatter-gather feature.

 I have segregated storage pools both for the requests (using the
 CustomHandler api) and the message headers, the data is taken directly
 from external buffers.

 I think that this is the most memory efficient I can go with the current
 version. Unfortunately there is a missing feature for me.

 Let's say that I hypothetically want to transfer a 100Mb file in chunks of
 512 bytes (payload). In my platform (linux) each handler is 92 bytes.

 If I submit all the work at once that means (104857600 bytes) / (512
 bytes/chunk) = 204800 chunks, which equals 204800 * 92 = 18841600 bytes,
 18Mb of stored handlers more or less.

 It would be very handy to have a way to separate the individual non-
 blocking udp transfers (calls to the underlying udp socket API) in a
 ConstBufferSequence just using a single handler/request. That would give
 more reasonable memory requirements.

 With tcp this isn't a problem, it is a matter of passing all the sequence
 and forget about it.

 Unfortunately the typical use case of UDP is a bit different, control over
 the datagram size is needed, and with the current implementation the only
 way to go is suboptimal.

 Two ideas come to my mind, knowing next to nothing about the library
 internals:

 -To add another overload to async_sent_to, which specifies a numeric
 parameter saying how many buffers belong to each udp tranfer.

 -To add a new Sequence type (would make sense when using tcp?), or a
 buffer type that is a separator/delimiter.

 I was just curious and I modified the source a little using the first
 approach, unfortunately I had no time to figure out how could it work in
 windows as it wasn't as obvious, so I desisted because I need to support
 both platforms.

 What i did was a new class/file
 "detail/asio_reactive_socket_send_to_periodic.hpp" copying the source code
 of "detail/asio_reactive_socket_send_to.hpp", adding a template parameter
 named "BuffersPerDatagram" and modifying the "do_perform" function. I used
 a stl container as ConstBufferSequence:

 static bool do_perform(reactor_op* base)
 {
         reactive_socket_sendto_periodic_op_base* o(
 static_cast<reactive_socket_sendto_periodic_op_base*>(base));

         bool result = true;
         typename ConstBufferSequence::iterator it = o->buffers_.begin();

         std::size_t bytes_transfered = 0;

         while (result && (it != o->buffers_.end()) && !o->ec_)
         {
                 boost::array<typename ConstBufferSequence::value_type,
 BuffersPerDatagram> arr;

                 for (std::size_t i = 0; i < BuffersPerDatagram; ++i)
                 {
                         std::memset (&arr[i], 0, sizeof (typename
 ConstBufferSequence::value_type));
                         if (it != o->buffers_.end())
                         {
                                 arr[i] = *it;
                         }
                 }

                 buffer_sequence_adapter<boost::asio::const_buffer,
                         ConstBufferSequence> bufs(arr);

                 result = socket_ops::non_blocking_sendto(o->socket_,
                           bufs.buffers(), bufs.count(), o->flags_,
                           o->destination_.data(), o->destination_.size(),
                           o->ec_, bytes_transfered);

                 o->bytes_transferred_ += bytes_transfered;
         }

         return result;
 }

 After this it was a matter of call forwarding, but because I don't know
 the code base and what exactly does I preferred to submit a feature
 request, as I'm not the only one that found this limitation:

 http://comments.gmane.org/gmane.comp.lib.boost.asio.user/2987

 It starts after the third message.

 If help is needed to implement it I can do it if someone that has the
 library knowledge guides me.

 Of course I can be missing an alternate way of doing things too. I did
 some research before posting and I wasn't able to find a way.

 Best regards!
 Rafa

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/7837#comment:1>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:11 UTC