From: Don G (dongryphon_at_[hidden])
Date: 2005-04-23 00:19:50
I hope all is going well.
> That said I am trying to find out what your library
> offers to understand if it belongs to the same package
> which is called "ace" right now. Or your library has
> different goals which means we need another package in
> level 1 or even worse a new level. In the end the
> network library can and should consist of different
> packages to meet different requirements but it should
> be very clear to library users which requirements are
> met by each package.
I agree on the goals for each package. The library I am proposing is
logically the same as sockets, but of course, it must be implemented
somehow (sockets typically). Ideally, there would be nothing between
it and the most primitive/best-performing library available. Various
implementations of the interfaces would map to whatever mechanism was
available (see below).
> As far as I understand the acceptor-connector pattern
> the idea is that a connector behaves like an acceptor.
> This means both of them are factories producing
> connected streams. Most network developers (who know
> Berkeley sockets) will probably create an acceptor
> based on accept() and a connector based on connect().
> The acceptor will work as a factory but the connector
> can probably be used only once to create one connected
The reason I suppose that I preferred not-yet-connected as a state of
stream (vs. a separate class) is that it is logically a 1-to-1
relationship (and even the same socket) whereas acceptor is a 1-to-N
relationship (the acceptor socket never becomes something else).
The other reason I went with the approach I have is that there is
only one object to deal with for cancel. I don't need to worry about
the transition from connecting to connected when I want to abort.
> This is what I did in
> http://www.highscore.de/boost/net/basic.png and comes
> close to the C API. If we think of unexperienced
> developers who don't know any sockets they will
> probably be happy if the connector behaves like the
> acceptor as they wouldn't understand the difference.
I would find this more difficult. With an acceptor, I am doing one
thing (accepting connections), but with _each_ stream connection, I
am doing one thing. In this respect, the socket approach feels right:
an acceptor is a thing, and a not-yet-connected stream is also its
own thing (which may become connected eventually).
> Regarding the acceptor and connector your library
> seems to be close what I made up in the class
> hierarchy and therefore would belong to level 0.
I think that is consistent in that it is an attempt to hide sockets
which is at level 0 (maybe they will move down to -1<g>).
>> My goal is to iron out a behavior contract that
>> satisfies various possible and desired
>> implementations, so that a library user can know
>> what are safe and portable practices. One could
>> say that the sockets API does this, but there are
>> two central issues: one cannot create a new type
>> of socket (to layer protocols); not all forms of
>> I/O completion are portable.
> I am surprised to read this! The socket API - the
> so-called level 0 - must and will be portable. It
> should be possible to derive classes from socket
> and create new types. And all four types of I/O
> must be supported in level 0, too. What kind of
> problems do you see here?
Some platforms have socket features that aren't available on other
platforms. Unix has signal-driven I/O, while Windows does not.
Windows has event object based I/O, completion ports, HWND messages,
etc. which are unique to it. The common intersection is blocking,
non-blocking and select. One can write 99% portable sockets code
based on that subset.
Except that Windows has restrictions on select(). A single fd_set
must be <= 64 sockets. You cannot mix sockets from different
providers (which I understand to mean IPv4 vs. v6 vs. IPX vs.
whatever). Also, select() is for sockets only, not files, not pipes,
One cannot make a sockets layer that hides these issues without
violating the spirit of this layer: thin.
Hence, my proposal. I believe the right answer is to write an ideal
network interface. One that focuses on behaviors and not the API's
used to implement them. On some platforms, this implementation can be
fairly thin. Of course, it can also provide a robust thread-pooling
implementation and probably has to on Windows (because of the 64
socket limit). On Linux, it could use epoll. All are wonderful areas
Which brings me to notification via callback. Whenever user code is
called by a library, there must be clear rules and expectations. One
good way to make things difficult would be to make callbacks to user
code from a signal handler. Of course, threads can also present a
It is all well and good to provide choices to the application author,
but we cannot forget the vital role of protocol library authors. So,
what I think is necessary is a description of rules and things one
can expect when using async calls specifically. Without clear and
unequivocal rules, protocol library authors would have to constantly
wonder about these important details.
So, let's pick on an SSL stream implementation based on OpenSSL.
IMHO, the ideal implementation of such a thing would consume an
abstract stream (so it could be used over any arbitrary transport)
and provide the same stream features. Since this is a user library,
the OpenSSL stream is not a socket. It cannot create some entity that
can be passed to the socket API. This is what I meant by "we cannot
create new kinds of sockets". Further, because the SSL stream makes
I/O requests, it must understand what is supported and how async
callbacks work. It must present exactly those same behaviors to its
> If the network library should support platform-specific
> features we should indeed add another package to
> http://www.highscore.de/boost/net/packages.png. This
> package would be optional. However it would be nice if
> classes from this package would collaborate somehow
> with classes from the other non-optional packages of
> the network library. The non-optional packages would
> provide a default implementation and library users
> could use optimized classes from the optional package
> depending on the platform they are using.
I agree (I think<g>). There will always be non-portable concerns and
one can always address them by writing directly to the API for the
platform. Once a library is interposed, things change. What I was
expecting in this area was that the lowest-level API wrappers (mostly
sockets) are entities that can be used in platform-specific ways
because they provide their native descriptor to the user.
But, this is a "chose your layer and portability goals" question for
the app. To exercise such features, one will have to go around the
interfaces I am proposing.
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk