Re: [asio-users] message (datagram) oriented tcp protocol with asio
Brought to you by:
chris_kohlhoff
From: James F. <jam...@nd...> - 2014-02-04 22:14:04
|
On Fri, Jan 17, 2014 at 6:10 PM, Marat Abrarov <ab...@ma...> wrote: > Hi. James. > > > So rather than chat working "on top" of ASIO, we extend ASIO > > to support the "chat socket" as an extension of ASIO. > > > > I think this could be "faked" by making chat::socket a "thick" > > implementation that simply wraps multiple use of asio::ip::tcp > > similar to how the current chat example is written. I believe > > this would require handler storage or "chaining", where the > > handler used for the tcp socket async_receive() was given the > > handler passed into chat::scocket::async_receive(). But this > > doesn't really seem to be the ASIO way. > > > Has this been done? Does it sound like it would be a good idea > > to do? I think it could be generalized for the class of > > protocols with fixed length headers, and probably for the class > > of delimited header/body protocols as well. Then chat would be > > something like: > > Splitting of the TCP stream into the frames (actually we are speaking > about reading from stream frame by frame, frame at once) can be implemented > (frame protocol "header with payload size + payload") by the > asio::async_read free function with special CompletionCondition functor: > > http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/async_read/overload2.html > . > > But this is rarely (IMHO) used because of: > 1. Often it is important to register every (!) async_read_some completion > for timeout reasons (to register timeout and abort any subsequent > operations, may be this can be achieved by asio::async_read free function > too). > 2. The most widely used mode is to read (from socket, e.g. from kernel > space into the user space) as much as the buffer of application supports > and then parse the read data to get some frames/messages (the last one may > be incomplete or it may be (still) no complete messages in the buffer at > all). This "mode" has to minimize kernel/user space switches (there are > some articles about it in the internet). > I had overlooked the asio::async_read free function with the CompletionCondition functor. Thanks for pointing that out. It does seem to handle a fixed-size header style protocol fairly well. I understand your concern (#2) with performing small reads and thus many context switches. I do not follow the concern (#1) about timeouts; I believe you could still cancel() or close() the socket, though it might be tricky to pass enough information (num bytes read) on for recovery. As a proof of concept, I adapted the chat client example to use a templated base class that performs the two-phase read using the async_read free function. The chat client itself now makes a single async call with a single handler that is invoked when the entire message is available. See: https://github.com/jflemer/boost-chat-server This is only a quick demo, I did not adapt the server part nor the writes. There are some frustrating issues with boost bind passing the handler through another handler; I used a mix of std::bind and boost::bind to get around it, though there is probably a better way. -James |