Doc. no:  N1974=06-0044
Date:     2006-03-31
Project:  Programming Language C++
Reply to: Christopher Kohlhoff <chris@kohlhoff.com>

Boost Network Library Query

Boost (www.boost.org) has recently accepted the asio asynchronous I/O library, and there are plans to morph this library into a full-fledged networking library. Because the C++ committee [N1810] has specifically identified networking as an area of interest, part of the development process could be to prepare a TR2 proposal for the library.

The purpose of this query is threefold:

Overview

To give some idea of the flavour of the asio library, consider the following sample code. This is part of a server program that echoes characters it receives back to the client in upper case:

template <typename Iterator>
void uppercase(Iterator begin, Iterator end)
{
  std::locale loc("");
  for (Iterator iter = begin; iter != end; ++iter)
    *iter = std::toupper(*iter, loc);
}

void do_sync(
    asio::ip::tcp::socket& socket,
    std::vector<char>& buffer_space)
{
  try
  {
    for (;;)
    {
      std::size_t count = socket.read_some(asio::buffer(buffer_space));
      uppercase(buffer_space.begin(), buffer_space.begin() + count);
      asio::write(socket, asio::buffer(buffer_space, count));
    }
  }
  catch (asio::error& e)
  {
  }
}

The synchronous approach used above is straightforward to understand and easy for programmers at any level of ability to write.

Next, the equivalent code developed using asynchronous operations:

void do_async(
    asio::ip::tcp::socket& socket,
    std::vector<char>& buffer_space)
{
  socket.async_read_some(asio::buffer(buffer_space),
      boost::bind(handle_read, _1, _2,
        boost::ref(socket), boost::ref(buffer_space)));
}

void handle_read(
    const asio::error& e,
    std::size_t count,
    asio::ip::tcp::socket& socket,
    std::vector<char>& buffer_space)
{
  if (!e)
  {
    uppercase(buffer_space.begin(), buffer_space.begin() + count);
    asio::async_write(socket, asio::buffer(buffer_space, count),
        boost::bind(handle_write, _1,
          boost::ref(socket), boost::ref(buffer_space)));
  }
}

void handle_write(
    const asio::error& e,
    asio::ip::tcp::socket& socket,
    std::vector<char>& buffer_space)
{
  if (!e)
  {
    socket.async_read_some(asio::buffer(buffer_space),
        boost::bind(handle_read, _1, _2,
          boost::ref(socket), boost::ref(buffer_space)));
  }
}

This code may appear more complex due to the inverted flow of control, but it allows a knowledgeable programmer to write code that will scale to a great many concurrent connections. The synchronous code requires one thread for each connection, and on most platforms threads are a limited resource. The asynchronous approach offered by asio has been exercised in production HTTP servers to thousands of concurrent connections, and similar echo servers have been tested to tens of thousands, while using only one thread.

Q & A

Motivation and Scope

What kinds of problems will it address?

The problem areas addressed by this library include:

What are some problems it won't address?

Problems that are considered outside the scope of the proposal include:

What kinds of programmers is it intended to support? Novice? Everyday? Experts?

The bulk of the library interface is intended for use by developers with at least some understanding of networking concepts (or a willingness to learn). A high level iostreams interface supports simple use cases and permits novices to develop network code without needing to get into too much depth.

Is it based on existing practice?

The asio library, from which this proposal is derived, has been deployed in a number of production systems, such as internet-facing HTTP servers, instant messaging gateways and finance applications.

The interface is based on the BSD sockets API, which is widely implemented and supported by extensive literature. It is also used as the basis of networking APIs in other languages (e.g. Java). Unsafe practices of the BSD sockets API, e.g. lack of compile-time type safety, are not included.

Asynchronous support is derived from the Proactor design pattern as implemented by the ADAPTIVE Communication Environment [ACE], and is influenced by the design of the Symbian C++ sockets API [Symbian], which supports synchronous and asynchronous operations side-by-side.

Is there a reference implementation?

The proposal will be based on the Boost.Asio library (asio.sourceforge.net).

What platforms are currently supported?

The asio library currently supports the following platforms and compilers:

What platforms or environments are likely to be difficult or impossible to support?

The library would not support platforms where native networking facilities are unavailable. The library is not intended to support platforms without native TCP/IP networking, although one could imagine a user-mode TCP/IP stack as part of an implementation of the library.

Impact On the Standard

What does it depend on, and what depends on it?

Minor parts of this library proposal depend on the TR1 library extensions for Enhanced Binders (N1455) and Fixed Size Array Wrapper (N1479). It also depends on the proposed Date-Time library extension (N1900).

This proposal does not require, and would not be coupled to, hypothetical standard library support for threading. The interface is intended to support implementations on platforms where threads are not available. However, it is designed to allow the effective utilisation of threading if available, and its behaviour with respect to threads is clearly defined.

Is it a pure extension, or does it require changes to standard components?

This is a pure library proposal. It does not add any new language features, nor does it alter any existing standard library headers.

Can it be implemented using today's compilers, or does it require language features that will only be available as part of C++0x?

This library can be implemented using compilers that conform to the C++03 standard. An implementation of this library requires operating system-specific functions that lie outside the C++03 standard.

Design Decisions

Will it support both synchronous and asynchronous networking?

Yes.

Asynchronous support is particularly important because it allows applications to leverage concurrency without threading.

The library offers side-by-side support for synchronous and asynchronous operations. These operations may be composed in a logically similar way to create higher levels of abstraction (e.g. an HTTP library) that offer both synchronous and asynchronous support.

What protocols will it support?

At a minimum, TCP and UDP for both IP versions 4 and 6. It will enable the development of protocol independent applications, in that the decision to use IPv4 or IPv6 can be deferred until runtime.

Does it take advantage of operating system specific APIs and  other features?

The library interface does not include operating system specific APIs. The interface is designed to allow flexibility of implementation, so that operating system specific APIs may be used internally to deliver optimal outcomes in performance and scalability. The interface also permits implementation-specific extensions (e.g. support for UNIX domain sockets) in a manner that is consistent with the standard functionality.

Does is support both client-side and server-side applications?

Yes.

Is it modern C++? Does it play well with the standard library?

The library aims to reduce sources of error by using approaches such as RAII and exception handling as a default error mechanism. The asynchronous interface is based around function objects as callbacks, and is typically used in conjunction with an implementation of Enhanced Binders (N1455).

Is it layered into low-level, mid-level, and high-level components?

The primary focus of the library is on a lower level interface, based on the BSD sockets API, that is aimed at experienced and expert developers. For flexibility and maximum utility, it is specified at the lowest level of abstraction that allows efficient implementation of both synchronous and asynchronous operations on major platforms. This interface can be used to develop other libraries at higher levels of abstraction.

Additionally, an iostreams interface is layered on top of the lower level interface. It is intended for simple use cases and novice developers.

If there are any similar libraries in use, how do their design decisions compare?

Unlike ACE, this library chooses not to expose the mechanism by which asynchronous operations are initiated. Furthermore, ACE does not guarantee that asynchronous operations will be available on a particular platform, whereas this proposed library does (the reference implementation demonstrates that asynchronous I/O can be efficiently emulated when native support is unavailable).

Like Symbian, the interface does not provide reactive I/O.

Feedback channel

It would be helpful to the developer to be able to obtain email feedback from the LWG from time to time. Would the LWG prefer use of the regular library reflector, a separate mailing list (perhaps hosted by Boost), or some other solution?


[N1810] Library Extension TR2 Call for Proposals, www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1810.html