
There has been some discussion on this on the list lately. Is there anyone working on it. I have been pondering an interface that supports both async and blocking io combined. And an event dispatching model that can handle several types of dispatching mechanism through a the same interface to provide for a lot of differnet implementations. At heart of this is an io_stream base class that should serve as base for classes like tcp_stream and udp_stream. class io_stream : public event::event_handler { public: // blocking read virtual io_result read( void* buffer, size_t byteCount) = 0; // blocking write virtual io_result write( const void* buffer, size_t byteCount) = 0; // asynchrounous read. virtual io_result async_read( void* buffer, size_t byteCount, boost::function<void(const io_result&)>) = 0; // asynchrounous write. virtual io_result async_write( const void* buffer, size_t byteCount, boost::function<void(const io_result&)>) = 0; virtual void close() = 0; protected: }; the event_handler interface is at heart of event handling and dispatching. class event_handler { ublic: virtual ~event_handler(); // returns a pointer to the dispatcher the source // is attached to or NULL if the source isn't attached. event_dispatcher* dispatcher(); protected: enum event_type_t { read_event, // A read can be done without blocking read_done_event, // An async read is completely done write_event, // A write can be done without blocking write_done_event, // An async write is completely done connect_event, accept_event }; typedef std::bitset<6> event_set_t; // returns the current set of events we want to receive event_set_t event_filter() const; // updates the current event set by oring // current filter and the set provided void update_event_filter(event_set_t set); // an opaque handle to the underlying source virtual void* handle() = 0; /// callack when event occurs. /// event - type of event dispatched /// bytes - number of bytes affected by the event /// size_t(-1) if unknown. /// error - an event specific error code 0 if no error /// eventData - a void* pointer that contains opaque /// data supplied when initiating the operation NULL of none /// is supplied or not available void dispatch_event( event_type_t event, size_t bytes, unsigned int error, void* eventData) = 0; private: event_handler(const event_handler&); event_handler& operator=(const event_handler&); }; From this we could be notified both of full async completes or just ready to write and ready to receive. And when a concrete io_stream implementation receives notification it can check on the flags if the read have completed or of we must do a read or write to fullfill the pending operation that must be stored within the implementation. This makes for implementations of the event dispatcher (including simple select, kqueue, iocp or some other mechanism both edge and level triggered). The event dispatcher interface looks like: class event_dispatcher { public: /// attaches an event handler to an dispatcher /// all dispatchable events for the event handlers /// handle will go through this dispatcher. an event handler /// and its associated handle is attached /// to a specific dispatcher throughout its life time virtual void attach(event_handler& source); /// Removes an event handler from set. notifications /// wont be sent to this dispatcher to the event handler /// after this point. virtual void detach(event_handler& source); /// notify the event_dispatcher that the event filter /// has changed for the given source virtual void notify(event_handler& source); /// dispatch pending events blocks timeoutSecs waiting /// for event. returns true if an event was dispatched /// during the call. virtual bool dispatch_event(unsigned int timeoutMsecs); /// adds a callback to be called asynchrounously the next /// as soon as possible. virtual void asynch_dispatch(boost::function<void> callback); }; This can be implemented in various ways through simple select for single threaded version, and leader follower select for multithreaded with several threads hanging in dispatch_events and handling and event and promoting a new leader to catch next set. And it could be implemented using io completion ports or kqueue for scalable variants. To top this of we have connector and acceptor base classes class connector : public event::event_handler { public: std::auto_ptr<net::io_stream> connect_stream() = 0; void async_connect_stream( boost::function<void(const io_result&, std::auto_ptr<net::io_stream>)> callback) = 0; }; class acceptor : public event::event_handler { public: std::auto_ptr<net::io_stream> accept_stream() = 0; void async_accept_stream( boost::function< void(const io_result&, std::auto_ptr<net::io_stream>)> callback) = 0; }; And tcp_acceptor and tcp_connector to implement these for tcp. Eg the tcp acceptor: class tcp_acceptor : public acceptor { public: acceptor(const ip_endpoint& localEndPoint); acceptor(event::event_dispatcher& dispatcher, const ip_endpoint& localEndPoint); std::auto_ptr<net::tcp_stream> accept() = 0; void async_accept( boost::function<void(const io_result&, std::auto_ptr<net::tcp_stream>)> callback) = 0; /// Acceptor functions std::auto_ptr<net::io_stream> connect_stream() = 0; void async_connect_stream( boost::function<void(const io_result&, std::auto_ptr<net::io_stream>)> callback) = 0; }; I think these interfaces would allow for a range of implementations under the same umbrella. The os dependent sockets part should be handled by a socket facade class. The io_result class is a helper class that handles reporting of the actual result and eventual error outcome of an operation. It combines error codes and exception throwing. // encapulates a result of an net operation // throws an io_error if none of the following // members haven't been called before destruction: // failed,success,error_code,throw_exception. struct io_result { enum error_code_t { e_success, e_cancelled, // operation was cancelled e_pending_io // an net operation of the specified type is already pending }; error_code_t error_code() const; bool failed() const; bool success() const; void throw_exception() const; // bytes transferred by the last operation size_t byte_count() const; }; So this is the outline of an interface that I think could serve as a foundation for a net library. I will try to go about and implement prototype for this using both select and iocp. But there are some things to iron out such as thread saftey and such (since it will necessary to at least having several threads blocking in dispatch_event at least the event_dispatcher would have to be thread safe and probably parts of the event source d). What are your initial thaugths on this, implementatble? flexible enough? efficient enough? What are you others doing in this field? And maybe we should do something together instead if we are sitting in different cornes hacking on something similar. I know for one i need help with boost.build, how to produce documentation according to boost standard, multi platform testing and the like ;). Regards /Michel

Michel André wrote:
There has been some discussion on this on the list lately. Is there anyone working on it. I have been pondering an interface that supports
Yes, but I had no time lately. See http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostNet for what we have now. However I still have to update the page after the socket/async IO/pure async discussions to add latest thoughts.
both async and blocking io combined. And an event dispatching model that can handle several types of dispatching mechanism through a the same interface to provide for a lot of differnet implementations.
At heart of this is an io_stream base class that should serve as base for classes like tcp_stream and udp_stream.
The interface of io_stream looks good. This class is called socket in the UML diagram you find at the bottom of http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostNet.
[...] the event_handler interface is at heart of event handling and dispatching.
Is the event_handler exposed to the library user or an idea how to implement the event stuff internally? At first I thought it's an implementation detail but after thinking a while it looks like an object-oriented select() replacement?
[...] To top this of we have connector and acceptor base classes
Your connector and acceptor are inherited from event_handler compared to the class hierarchy at the bottom of http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostNet where they are inherited from socket. Your design is similar to the one in .NET where TcpClient and TcpListener use Socket but are not inherited from Socket. I have no opinion right now which one to favor - I guess it comes down to definitions and concepts. I'll think about it. :-)
[...] What are your initial thaugths on this, implementatble? flexible enough? efficient enough?
Your design comes close to what we have in the Wiki. After the long discussions about async I/O and a pure asynchronicity library I would like to see an asynchronous design pattern for Boost first that not every library reinvents interfaces for asynchronous operations. Besides that someone proposed to concentrate on an async I/O library first and base the asynchronous operations of a network library on this. You started to create an interface for async I/O already so maybe you can decouple it (or is this the event_dispatcher/event_handler part?). I'll try to update the Wiki page about the network library as soon as possible to give a summary about what has been discussed in the async threads. If you have time please read http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostNet - I look forward to your feedback. Boris

Boris wrote:
The interface of io_stream looks good. This class is called socket in the UML diagram you find at the bottom of http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostNet.
Yes, I tried do have a more abstract notion than socket which is quite concrete to me and one way of implementing an io_stream.
[...] the event_handler interface is at heart of event handling and dispatching.
Is the event_handler exposed to the library user or an idea how to implement the event stuff internally? At first I thought it's an implementation detail but after thinking a while it looks like an object-oriented select() replacement?
It should be exposed and could be used to hook other things to the event dispatcher (of course this would maybe need a custom event_dispatcher or some knowledge of the implementation of the event_dispatcher).
Your connector and acceptor are inherited from event_handler compared to the class hierarchy at the bottom of http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostNet where they are inherited from socket. Your design is similar to the one in ..NET where TcpClient and TcpListener use Socket but are not inherited from Socket. I have no opinion right now which one to favor - I guess it comes down to definitions and concepts. I'll think about it. :-)
Yes i wanted to separate connection establishment and the stream handling completely since it's typically often the case for a server that you initiate listening on some well defined end points on different protocols and then like the actual connections and byte stream protocols to be alike irrespective of how the connection/stream was constructed. The socket class hierarchy doesn't make sense to me given we an acceptor inheriting from socket which would have send and receive ops but send and recv arent allowed on a listening socket only accept.
[...] What are your initial thaugths on this, implementatble? flexible enough? efficient enough?
Your design comes close to what we have in the Wiki. After the long discussions about async I/O and a pure asynchronicity library I would like to see an asynchronous design pattern for Boost first that not every library reinvents interfaces for asynchronous operations. Besides that someone proposed to concentrate on an async I/O library first and base the asynchronous operations of a network library on this. You started to create an interface for async I/O already so maybe you can decouple it (or is this the event_dispatcher/event_handler part?).
I don't think its possible or feasible to decouple the event handling completely since at least all notifications mechanisms for io handles fds that I know of is tigthly couple to platform specific primitives like iocp/kqueues/select and its not that easy to mix and match events at least not on all mechanisms and plattforms.
I'll try to update the Wiki page about the network library as soon as possible to give a summary about what has been discussed in the async threads. If you have time please read http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostNet - I look forward to your feedback.
Thanks I looked at it and it gives a good overview. I think this one gives a good summary as well http://www.kegel.com/c10k.html. I'm notto fond of the hierarchy of sockets as I mention above eg you cant read write from an listening socket, although i think the taxonomy of the hierarchy is great. /Michel

Hi Andre, Michel André wrote:
[...] The socket class hierarchy doesn't make sense to me given we an acceptor inheriting from socket which would have send and receive ops but send and recv arent allowed on a listening socket only accept.
read and write operations are still missing in this class hierarchy which I agree is not helpful. :) Actually I didn't plan to add them to class socket but only to class datagram, passive and connector. Maybe it makes sense to create an iosocket class which provides read and write operations and inherit datagram, passive and connector from it. In your design you don't inherit connector from io_stream for the only reason because you don't and can't do so with acceptor? Boris

Boris wrote:
read and write operations are still missing in this class hierarchy which I agree is not helpful. :) Actually I didn't plan to add them to class socket but only to class datagram, passive and connector. Maybe it makes sense to create an iosocket class which provides read and write operations and inherit datagram, passive and connector from it. In your design you don't inherit connector from io_stream for the only reason because you don't and can't do so with acceptor?
No it is to completely decouple connection establishment both on the server and the client from the actual stream or connection interface. The force behind this is that often the configuration of protocols and adresses is done quite far away from the stream and actual protocol needed. Usually its set up during init of server from a config file. The configurator could then set up a couple of acceptors and or connectors and send them away to the logic of the server that don't need to care about addresses or protocols and they act as factories for new streams. /Michel

Michel André wrote:
Boris wrote:
read and write operations are still missing in this class hierarchy which I agree is not helpful. :) Actually I didn't plan to add them to class socket but only to class datagram, passive and connector. Maybe it makes sense to create an iosocket class which provides read and write operations and inherit datagram, passive and connector from it. In your design you don't inherit connector from io_stream for the only reason because you don't and can't do so with acceptor?
No it is to completely decouple connection establishment both on the server and the client from the actual stream or connection interface. The force behind this is that often the configuration of protocols and adresses is done quite far away from the stream and actual protocol needed. Usually its set up during init of server from a config file. The configurator could then set up a couple of acceptors and or connectors and send them away to the logic of the server that don't need to care about addresses or protocols and they act as factories for new streams.
I think we have the same goal. While in my class hierarchy basically everything is a socket and a few classes have I/O operations you go the other way round: All socket classes have I/O operations and if a class doesn't do any I/O it isn't a socket (but a connector, acceptor or anything else). One problem I see with your design is that you have to implement some operations in non-socket classes like connector and acceptor separately, eg. close(). To implement close() is easy of course but I hope you get the idea. On most operating systems connectors and acceptors will make use of file descriptors just like other socket classes. We can reuse code with inheritance and just add I/O operations to the few socket classes which really do I/O. In the class hierarchy at http://www.highscore.de/boost/net/basic.png these classes would be datagram, passive and connector. There you can also see that the parent class socket provides a close() method which is inherited by all other classes including acceptor and connector. Boris

Boris wrote:
Michel André wrote: One problem I see with your design is that you have to implement some operations in non-socket classes like connector and acceptor separately, eg. close(). To implement close() is easy of course but I hope you get the idea. On most operating systems connectors and acceptors will make use of file descriptors just like other socket classes. We can reuse code with inheritance and just add I/O operations to the few socket classes which really do I/O. In the class hierarchy at http://www.highscore.de/boost/net/basic.png these classes would be datagram, passive and connector. There you can also see that the parent class socket provides a close() method which is inherited by all other classes including acceptor and connector.
I think we are on the same page basically, but different modelling tecqniques. Actually close will only be forwarding to socket::close. Since the connector will own one or more socket instances, and the acceptor will have one socket instance. The socket is a facade on the socket api. So it will be quite easy to handle in my design with some one liners. But I'm not that fond of deep inheritance hierachies and event thaugt about having a has-a relationship instead of inheritance to the event_source as well. Another slight mishap is that the things you call acceptor and connector arent acceptors and connectors in the sense of the original pattern (http://www.cs.wustl.edu/~schmidt/PDF/Acc-Con.pdf or POSA 2) as I interpret it. /Michel

Michel André wrote:
[...] Another slight mishap is that the things you call acceptor and connector arent acceptors and connectors in the sense of the original pattern (http://www.cs.wustl.edu/~schmidt/PDF/Acc-Con.pdf or POSA 2) as I interpret it.
I read the 17 pages for a better understanding. And I think you are right that we use different definitions. In the paper acceptor and connector are factories while in the class hierarchy at http://www.highscore.de/boost/net/basic.png they are an endpoint of a communication link. While I understand that the acceptor-connector pattern makes sense I think we should use it in a level > 0. If you look at the connector for example (in the acceptor-connector pattern) it is used to establish a connection and then passes over the connection to a service handler to do the processing. If level 0 should be similar to Berkeley sockets (and as far as I understand this is one goal of level 0) I don't know why the connector shouldn't be able to do the processing after the connection is established. In this level processing basically means calling read() and write(). A service handler in the acceptor-connector pattern is probably something bigger than a socket? Using the acceptor-connector pattern in level 0 would work but would also make the design more complicated as it should be to convince network programmers to switch over to the C++ network library. Boris

Boris wrote:
Michel André wrote:
[...] Another slight mishap is that the things you call acceptor and connector arent acceptors and connectors in the sense of the original pattern (http://www.cs.wustl.edu/~schmidt/PDF/Acc-Con.pdf or POSA 2) as I interpret it.
I read the 17 pages for a better understanding. And I think you are right that we use different definitions. In the paper acceptor and connector are factories while in the class hierarchy at http://www.highscore.de/boost/net/basic.png they are an endpoint of a communication link. While I understand that the acceptor-connector pattern makes sense I think we should use it in a level > 0. If you look at the connector for example (in the acceptor-connector pattern) it is used to establish a connection and then passes over the connection to a service handler to do the processing. If level 0 should be similar to Berkeley sockets (and as far as I understand this is one goal of level 0) I don't know why the connector shouldn't be able to do the processing after the connection is established. In this level processing basically means calling read() and write(). A service handler in the acceptor-connector pattern is probably something bigger than a socket? Using the acceptor-connector pattern in level 0 would work but would also make the design more complicated as it should be to convince network programmers to switch over to the C++ network library.
It's all in a name ;) . Then I don't think they should be called connector and acceptor in level 0 since I was associating it to the patterns in POSA2 which I guess a lot of people are familiar with. And if we are going to implement these in level 1 it might be confusing to have the names with a different implementation in level0. I also think there are a lot of good ideas to use from POSA2 and ACE. The service handler is the implementation of the service and protocol over a stream i.e http service handler for an web server that parses and responds to http requests. /Michel

Michel André wrote:
[...] It's all in a name ;) . Then I don't think they should be called connector and acceptor in level 0 since I was associating it to the patterns in POSA2 which I guess a lot of people are familiar with. And if we are going to implement these in level 1 it might be confusing to have the names with a different implementation in level0. I also think there are a lot of good ideas to use from POSA2 and ACE.
Agreed. In the beginning acceptor and connector in http://www.highscore.de/boost/net/basic.png were called server and client until someone complained. Now I also like acceptor/connector better than server/client but if they remind developers of the acceptor-connector pattern that's no good. However I don't know any better name in the moment - if you have an idea please tell me. :) However I took over your ideas about ACE and updated the package diagram at http://www.highscore.de/boost/net/packages.png. If we forget about the two yellow packages for a moment: * The red package belongs to level 0. I changed the name and now call it berkeley to emphasize that this package contains a C++ API of what is known to many programmers as Berkeley sockets. The idea of this package is that network developers who glance at the C++ network library recognize many concepts and switch over. They should look at the documentation, see a class socket and think: "I know everything about sockets - I can use these classes immediately." * The blue packages belong to level 1. I introduced a new package called ace because of the acceptor-connector pattern which is used in ACE. This package is for network programmers who look at the documentation, see application-level concepts and think: "I can connect my application to the network without understanding sockets." * The other blue package called iostream is for network programmers who know std::iostream and would like to use something similar for synchronous I/O on the network. As someone proposed it would be nice to implement a streambuf class for network operations. The package names were made up on the spot - there are probably better ones. The design however comes close to what we had already in the Wiki (see http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostSocket): There are two levels described - one as a wrapper for the C API (the berkeley package), the other one for connector, acceptor and data connection (our ace package). BoostSocket/Streams is the iostream package in the diagram. The multiplexing library I once proposed myself is one of the four supported I/O models which can be used in level 0 (there must be something similar to select()) and in level 1 (if we follow ACE there will be something like the Reactor class). Any comments? I'd be happy to hear some ideas which might be missing in the big picture. Boris

Boris wrote:
Michel André wrote:
Agreed. In the beginning acceptor and connector in http://www.highscore.de/boost/net/basic.png were called server and client until someone complained. Now I also like acceptor/connector better than server/client but if they remind developers of the acceptor-connector pattern that's no good. However I don't know any better name in the moment - if you have an idea please tell me. :)
Wish I had ;). Actually I don't think there should be a specific inheritance hierarchy (I don't really see what benefits it would do for developers familiar with sockets). On level 0 just the class socket that mimicks berkely sockets quite closely but only adds raii and unified error reporting and exception based. (Or as in giallo http://cvs.sourceforge.net/viewcvs.py/giallo/giallo/boost/net/socket/socket....) /// Facade for the socket api class socket { socket( const address_family& address_family, const socket_type& type, const protocol& protocol); io_result bind(address& addr); io_result listen(size_t backlog); io_result accept(socket& client, address& add); io_result connect(address& add); io_result recv(void* data, size_t len, int flags=0); io_result send(const void* data, size_t len, int flags=0); static io_result gethostbyname( const std::string& host, std::string& h_name, std::vector<std::string>& h_aliases, // alternate names std::vector<address>& h_addr_list // known addresses ); ... } You get the idea.
However I took over your ideas about ACE and updated the package diagram at http://www.highscore.de/boost/net/packages.png. If we forget about the two yellow packages for a moment: * The red package belongs to level 0. I changed the name and now call it berkeley to emphasize that this package contains a C++ API of what is known to many programmers as Berkeley sockets. The idea of this package is that network developers who glance at the C++ network library recognize many concepts and switch over. They should look at the documentation, see a class socket and think: "I know everything about sockets - I can use these classes immediately." * The blue packages belong to level 1. I introduced a new package called ace because of the acceptor-connector pattern which is used in ACE. This package is for network programmers who look at the documentation, see application-level concepts and think: "I can connect my application to the network without understanding sockets."
The package names were made up on the spot - there are probably better ones. The design however comes close to what we had already in the Wiki (see http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostSocket): There are two levels described - one as a wrapper for the C API (the berkeley package), the other one for connector, acceptor and data connection (our ace package). BoostSocket/Streams is the iostream package in the diagram. The multiplexing library I once proposed myself is one of the four supported I/O models which can be used in level 0 (there must be something similar to select()) and in level 1 (if we follow ACE there will be something like the Reactor class).
This is as you state the same approach as outined in the BoostSocket writings and Hugo Duncan implemented in giallo (http://giallo.sourceforge.net/). I also think there is another fundamental question, should we go the route proposed in giallo which is template based or a more ineritance/interface based approach? As we have to do with network io virtual dispatch wouldn't be a problem? /Michel

Michel André wrote:
[...] Wish I had ;). Actually I don't think there should be a specific inheritance hierarchy (I don't really see what benefits it would do for developers familiar with sockets). On level 0 just the class socket that mimicks berkely sockets quite closely but only adds raii and unified error reporting and exception based. (Or as in giallo http://cvs.sourceforge.net/viewcvs.py/giallo/giallo/boost/net/socket/socket....) [...] You get the idea.
Yes, we have such a socket class in .NET, too (see http://www.highscore.de/boost/net/dotnetsockets.png). Currently I have no strong opinion if a socket hierarchy is better. However as we have different socket types with different behavior it might be reasonable to create different classes. But if they distinguish only slightly it's probably not worth the effort. I'll think about the interfaces and add some more methods. If in the end all classes look basically the same it makes sense to merge them into one socket class.
[...] I also think there is another fundamental question, should we go the route proposed in giallo which is template based or a more ineritance/interface based approach?
As far as I have seen in the Wiki Hugo used templates for protocols and addresses. Could there be any other use for templates? Maybe I can answer this question myself when I extend the socket hierarchy and try to add protocols and addresses somehow. Boris

Boris wrote:
Michel André wrote:
Agreed. In the beginning acceptor and connector in http://www.highscore.de/boost/net/basic.png were called server and client until someone complained. Now I also like acceptor/connector better than server/client but if they remind developers of the acceptor-connector pattern that's no good. However I don't know any better name in the moment - if you have an idea please tell me. :)
Wish I had ;). Actually I don't think there should be a specific inheritance hierarchy (I don't really see what benefits it would do for developers familiar with sockets). On level 0 just the class socket that mimicks berkely sockets quite closely but only adds raii and unified error reporting and exception based. (Or as in giallo http://cvs.sourceforge.net/viewcvs.py/giallo/giallo/boost/net/socket/socket....) /// Facade for the socket api class socket { socket( const address_family& address_family, const socket_type& type, const protocol& protocol); io_result bind(address& addr); io_result listen(size_t backlog); io_result accept(socket& client, address& add); io_result connect(address& add); io_result recv(void* data, size_t len, int flags=0); io_result send(const void* data, size_t len, int flags=0); static io_result gethostbyname( const std::string& host, std::string& h_name, std::vector<std::string>& h_aliases, // alternate names std::vector<address>& h_addr_list // known addresses ); ... } You get the idea.
However I took over your ideas about ACE and updated the package diagram at http://www.highscore.de/boost/net/packages.png. If we forget about the two yellow packages for a moment: * The red package belongs to level 0. I changed the name and now call it berkeley to emphasize that this package contains a C++ API of what is known to many programmers as Berkeley sockets. The idea of this package is that network developers who glance at the C++ network library recognize many concepts and switch over. They should look at the documentation, see a class socket and think: "I know everything about sockets - I can use these classes immediately." * The blue packages belong to level 1. I introduced a new package called ace because of the acceptor-connector pattern which is used in ACE. This package is for network programmers who look at the documentation, see application-level concepts and think: "I can connect my application to the network without understanding sockets."
The package names were made up on the spot - there are probably better ones. The design however comes close to what we had already in the Wiki (see http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?BoostSocket): There are two levels described - one as a wrapper for the C API (the berkeley package), the other one for connector, acceptor and data connection (our ace package). BoostSocket/Streams is the iostream package in the diagram. The multiplexing library I once proposed myself is one of the four supported I/O models which can be used in level 0 (there must be something similar to select()) and in level 1 (if we follow ACE there will be something like the Reactor class).
This is as you state the same approach as outined in the BoostSocket writings and Hugo Duncan implemented in giallo (http://giallo.sourceforge.net/). I also think there is another fundamental question, should we go the route proposed in giallo which is template based or a more ineritance/interface based approach? As we have to do with network io virtual dispatch wouldn't be a problem? /Michel

On Apr 11, 2005 5:58 PM, Michel André <michel.andre@swipnet.se> wrote:
There has been some discussion on this on the list lately. Is there anyone working on it. I have been pondering an interface that supports both async and blocking io combined. And an event dispatching model that can handle several types of dispatching mechanism through a the same interface to provide for a lot of differnet implementations.
[ proposed interface ]
Looks very nice. Simple design, with what looks to be a complete interface and plenty of room for plugging in platform-specifics. I like the attention to detail: accept and connect can of course block (can listen too?), so providing ways to call them asynchronously is a nice touch that is lacking in some "C++ sockets" implementations.
The io_result class is a helper class that handles reporting of the actual result and eventual error outcome of an operation. It combines error codes and exception throwing.
// encapulates a result of an net operation // throws an io_error if none of the following // members haven't been called before destruction: // failed,success,error_code,throw_exception.
What is the explanation for this behavior? The user may not ignore io_results?
So this is the outline of an interface that I think could serve as a foundation for a net library. I will try to go about and implement prototype for this using both select and iocp. But there are some things to iron out such as thread saftey and such (since it will necessary to at least having several threads blocking in dispatch_event at least the event_dispatcher would have to be thread safe and probably parts of the event source d).
Yes. If an event_handler for a particular connection is still running in one thread, you (probably) don't want to dispatch it again in another thread if the underlying OS event mechanism fires again for the same handle.
What are your initial thaugths on this, implementatble? flexible enough? efficient enough?
As I said above, I like it. -- Caleb Epstein caleb dot epstein at gmail dot com

Caleb Epstein wrote:
On Apr 11, 2005 5:58 PM, Michel André <michel.andre@swipnet.se> wrote: Looks very nice. Simple design, with what looks to be a complete interface and plenty of room for plugging in platform-specifics. I like the attention to detail: accept and connect can of course block (can listen too?), so providing ways to call them asynchronously is a nice touch that is lacking in some "C++ sockets" implementations.
Thanks. Yes I think its important that at least accept should be able to be done asynchronously so accepting connections can be done on the same thread pool as all other io. And event connecting asynch gives meaning and is important for crawlers and the like.
The io_result class is a helper class that handles reporting of the actual result and eventual error outcome of an operation. It combines error codes and exception throwing.
// encapulates a result of an net operation // throws an io_error if none of the following // members haven't been called before destruction: // failed,success,error_code,throw_exception.
What is the explanation for this behavior? The user may not ignore io_results?
Both that and its transportable to callbacks and separate threads and the user can elect to throw the error in his handler and do handle exceptions instead of codes cross thread.
Yes. If an event_handler for a particular connection is still running in one thread, you (probably) don't want to dispatch it again in another thread if the underlying OS event mechanism fires again for the same handle.
This is a real can of worms I'll tell you. Suppose you have a asynch read pending and i handling an async read and decide to close the connection since you got a logout pack or invalid data or something. If the handle is locked and you want to do a sync close (ie no more notifications after close and as a part of close all pending operations should fail) If having a lock when doing the close from within an handler you'll have a deadlock since the pending ops cant complete with failure. But we will have to think about how to solve this. Especially for iocp where the os holds the buffers until the notification is received. Maybe close shouldn't be allowed within read or write handlers hand need to be posted separatly asynch to the dispatcher. /Michel

Hi Michel, I have also been putting together some ideas which are similar to those you outlined, though perhaps at a higher level of abstraction. I will try to wrap up what I have and post it in the next day or two. I will also try to look more closely at your code.
From a quick read, it looks similar to the implementation path I had used at my work, but probably more flexible in how event_dispatcher relates to event_handler. I think there is a good likelihood that the two are complementary.
Some philosophy questions: 1. Should the network library provide different choices of implementation to the user? For the most part, the platform will dictate the available solutions, so having the user decide would make their code non-portable. [my thought so far is no] 2. Would it be better perhaps to only provide behavior choices (sync, async, non-blocking) as part of the interface? [my thought is yes] Best, Don
There has been some discussion on this on the list lately. Is there anyone working on it. I have been pondering an interface that supports both async and blocking io combined. And an event dispatching model that can handle several types of dispatching mechanism through a the same interface to provide for a lot of differnet implementations.
At heart of this is an io_stream base class that should serve as base for classes like tcp_stream and udp_stream.
<code omitted>
So this is the outline of an interface that I think could serve as a foundation for a net library. I will try to go about and implement prototype for this using both select and iocp. But there are some things to iron out such as thread saftey and such (since it will necessary to at least having several threads blocking in dispatch_event at least the event_dispatcher would have to be thread safe and probably parts of the event source d).
What are your initial thaugths on this, implementatble? flexible enough? efficient enough?
What are you others doing in this field? And maybe we should do something together instead if we are sitting in different cornes hacking on something similar. I know for one i need help with boost.build, how to produce documentation according to boost standard, multi platform testing and the like ;).
__________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

On Apr 12, 2005 12:17 AM, Don G <dongryphon@yahoo.com> wrote:
1. Should the network library provide different choices of implementation to the user? For the most part, the platform will dictate the available solutions, so having the user decide would make their code non-portable. [my thought so far is no]
I disagree. On some platforms, there are multiple choices for the underlying event dispatching implementation. For example, on Linux you can use select, poll, or on newer kernels, epoll and kqueue. Even on Windows, there is more than one implementation that can be used (e.g. WaitForMultipleObjects, select (which I assume just wraps WFMO), and IO Completion Ports). Some of these are semi-portable (e.g. select, poll) but the others are very specific to the platform. As a user I want the ability to choose the one that is most suitable to the task at hand.
2. Would it be better perhaps to only provide behavior choices (sync, async, non-blocking) as part of the interface? [my thought is yes]
Not sure what you mean here. Connections may be either synchronous or asynchronous? This seems too limiting IMHO. -- Caleb Epstein caleb dot epstein at gmail dot com

Caleb Epstein wrote:
On Apr 12, 2005 12:17 AM, Don G <dongryphon@yahoo.com> wrote:
1. Should the network library provide different choices of implementation to the user? For the most part, the platform will dictate the available solutions, so having the user decide would make their code non-portable. [my thought so far is no]
I disagree. On some platforms, there are multiple choices for the underlying event dispatching implementation. For example, on Linux you can use select, poll, or on newer kernels, epoll and kqueue.
Even on Windows, there is more than one implementation that can be used (e.g. WaitForMultipleObjects, select (which I assume just wraps WFMO), and IO Completion Ports).
Some of these are semi-portable (e.g. select, poll) but the others are very specific to the platform. As a user I want the ability to choose the one that is most suitable to the task at hand.
But reasonable and efficient defaults should be used so you would not have to choose. Eg iocp on windows and kqueue on linux.
2. Would it be better perhaps to only provide behavior choices (sync, async, non-blocking) as part of the interface? [my thought is yes]
Not sure what you mean here. Connections may be either synchronous or asynchronous? This seems too limiting IMHO.
Aggreed you should be able to do eg synch/blocking write as a response to a asynch read, or do the handshaking/login synch and then go asynch. But I think most of the time the user will choos asynch or synch. /Michel

Don G wrote:
I have also been putting together some ideas which are similar to those you outlined, though perhaps at a higher level of abstraction. I will try to wrap up what I have and post it in the next day or two. I will also try to look more closely at your code.
It's not that much code more interfaces ;), but implementability on at least linux, solaris, windows is a minimum.
From a quick read, it looks similar to the implementation path I had used at my work, but probably more flexible in how event_dispatcher relates to event_handler. I think there is a good likelihood that the two are complementary.
Ok could you expand a bit? What do you mean by complementary?
1. Should the network library provide different choices of implementation to the user? For the most part, the platform will dictate the available solutions, so having the user decide would make their code non-portable. [my thought so far is no]
2. Would it be better perhaps to only provide behavior choices (sync, async, non-blocking) as part of the interface? [my thought is yes]
I think two but not providing choices just support them all automatically and efficiently. And give the user a possibilty to plugin own implementations of the concepts. /Michel
participants (4)
-
Boris
-
Caleb Epstein
-
Don G
-
Michel André