Boost logo

Boost :

Subject: Re: [boost] [Boost-users] Networking TS + Beast, NEW Tutorials, Read this to learn std::net !!!
From: Vinnie Falco (vinnie.falco_at_[hidden])
Date: 2019-03-15 14:43:03


On Fri, Mar 15, 2019 at 7:19 AM Stian Zeljko Vrba <vrba_at_[hidden]> wrote:

> > I believe it is wrong to blame Asio for this.
>
> I disagree. Recently, I've been coding parallel, including networked &
> asynchronous, programs in C# and Java, and the experience has been a JOY. You
> get threads, executors, synchronization primitives, tasks, cancellation,
> monadic futures and concurrent (blocking and non-blocking) data structures
> out of the box with the platform, plus a myriad of extensions as libraries.
> As for executors, you don't need to be bothered with them unless you really
> want to for some reason.
>

If you were to compare POSIX or BSD sockets to C# and Java, you would say
exactly the same things. Asio (like Beast) is a low-level, portable
abstraction of I/O. You can BUILD "threads", "executors", "synchronization
primitives", "tasks", "cancellation", "monadic futures", and "concurrent
data structures" with it. Does this mean OS-level sockets are the wrong
abstraction?

Of course not. The reason C# seems "ahead" of C++ is two-fold:

1. WG21 goofed up by delaying networking
2. C# is not developed through the International Standards Process

These mistakes are being fixed though, and you will see library support in
C++ catch up by leaps and bounds. And when we finally get these things
(built on top of Asio/Networking TS, which has proven over and over to be
the correct low-level abstraction) it will be better than C#, Java, or Rust.

Compare the documentation for Vertx (vertx.io) or netty (both Java toolkits
> for writing asynchronous reactive programs) with that of asio.
>

Yes I agree, there is a lack of documentation and especially tutorials for
beginners (which I am trying to fix). This has nothing to do with whether
Asio is the right portable, low-level abstraction (it is) but the lack of
guidance from the author could lead you to believe incorrect things about
the lib.

Once I attempted to write an asio service, tried to understand the simple
> example from the documentation, and I gave up. I used a thread, blocking
> call and CancelSynchronousIO (and I consider myself fortunate to develop
> for Windows only that has it).
>

The documentation on services is particularly scant. There is no
explanation of what they are for, how to use them, best practices, or even
"Frequently Asked Questions." I was able to figure it out though, but I am
able to focus all of my time on it.

> Asio _is_ a relatively nice wrapper around socket and serial port APIs,
> but that's about it
>

Yes now you're getting close to an accurate description. More correct would
be to say that Asio provides robust abstractions of buffers, dynamic
buffers, synchronous I/O, and asynchronous I/O. Networking is a subset of
that (but not the only part, see signals and serial ports, and soon file
I/O).

> IMO. On the other hand, I could have written the same wrappers around
> native APIs in two days and not haul along what I consider the baggage of
> technical debt that is asio in the codebase.
>

There is no API technical debt. That is to say, that the interfaces are
modern and up-to-date. You could argue that particular implementations such
as Boost.Asio have extra code to provide C++03 compatibility, but this has
nothing to do with the soundness of the design. As these interfaces are
part of a TS, there will be implementations in gcc and clang appearing
shortly (if not already so). These will be written from scratch so there
will be no support for older C++.

> Conclusion, if any: many people just want/need thread per client and
> synchronous IO for simplicity, but until asio/networking TS provide for
> timeouts and cancellation of synchronous requests, it's a wrong tool for
> those people, me included.
>

If you define

struct sync_socket
{
  net::io_context ioc_;
  net::ip::tcp::socket_;
  net::steady_timer timer_;
  ...
  template<class Buffers>
  std::size_t write_some (Buffers const& b);
};

You can easily implement timeouts in `write_some` thusly:

template<class Buffers>
std::size_t
sync_socket::
write_some (Buffers const& b, error_code& ec)
{
  std::size_t n;
  timer_.expires_after(seconds(30));
  timer_.async_wait(
    [&](error_code ec)
    {
      socket_.cancel(ec):
    });
  socket_.async_write_some(b,
    [&](error_code ec_, std::size_t n_)
    {
      ec = ec_; n = n_;
    });
    ioc_.run();
    return n;
}

Now, you can use `sync_socket` with all the usual sync write operations
like `net::write`, and get timeouts.

Thanks


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk