On 22/01/2015 12:56, David Hawkins wrote:
In theory the filtering_stream 'filter' and 'device' layers should pass characters, EOF, and WOULD_BLOCK. Unfortunately the code snippet I posted suppresses the propagation of the WOULD_BLOCK return value from the 'device' layer to the 'filter' layer.
Generally I would recommend using only blocking or async code. Non-blocking is a holdover from when async didn't really exist yet, and with ASIO you shouldn't have that excuse.
The Boost chat client/server has similar features to my problem, i.e., it involves encoding/decoding messages. The encoding/decoding is different than my case, since the chat protocol adds a header with the message length. This simplifies the socket read code, since you can read the fixed-length header, then read the now known) message length, i.e., each call to read has a fixed length parameter. In my case, the message length is unknown, and depends on the content of the message (since data can be escaped). The data stream is generated by a field-programmable gate array (FPGA), and adding a buffer to determine the message length before sending the response would use too many resources, so the encoding protocol cannot easily be changed.
My point is that theoretically this shouldn't be a problem, as long as the lowest level (actual device reading) behaves as described earlier. When you read(buffer, 512) it would block until the device provides some data; perhaps it sends a 28 byte packet, of which the driver eagerly grabs the first 8 bytes and so read() returns 8; you look at that data, decide it's not a complete message yet, so you stash it into a separate buffer and call read(buffer, 512) again. (There are other approaches if you want zero-copy.) This time the driver already had the remaining 20 bytes queued up and so read() immediately returns 20. You tack those bytes onto the end of your prior stash, parse the whole thing, and now you've got a message you can return to a higher layer, and then go back to reading. Async works similarly, you just break the code up a little more so that it can return while it's waiting. (Just remember that it might also return a few bytes from the start of the *next* message, so you need to strip exactly one message out of the stash and keep accumulating bytes for the next message.)