websockets icon indicating copy to clipboard operation
websockets copied to clipboard

Support receiving fragmented messages without reassembly

Open aaugustin opened this issue 7 years ago • 10 comments

Based on a suggestion by @cjerdonek in #296, I'm creating this new issue for clarity.

When receiving a fragmented message, it might be desireable to obtain the fragments without reassembling, to avoid a memory copy which may not be necessary.

Most likely this could be enabled by providing a variant of recv. I'd say it should be a separate function because it would have a different return type.

That function could return an async iterator (after we drop support for Python 3.4).

max_size should be re-interpreted as the maximum size of each chunk / frame rather than message.

The original suggestion was a file-like object. This needs some thought. It may require a layer of buffering which may negate the performance benefits.

aaugustin avatar Sep 23 '18 16:09 aaugustin

When receiving a fragmented message, it might be desireable to obtain the fragments without reassembling, to avoid a memory copy which may not be necessary.

To show another use case: Forwarding of messages with flow-control and a backpressure signal on a chunk level.

lgrahl avatar Oct 25 '18 14:10 lgrahl

Hello, are there any plans to go forward with this issue? It's great that we have a nice way to send fragmented messages, it'd be even greater to have it the other way round as well.

Perhaps the incoming queue should hold frames instead of messages. As you mentioned, each frame could be limited with max_size (for a frame now, not a message). read_message then could take frames from the queue instead of the socket. read_frame could become public API, it would get a frame from the queue. The queue should probably only hold data frames and control frames could be processed in the transfer_data task (or one of its callees probably). I may miss something, but it seems to be doable.

P.S. Merry Christmas!

dmitryduka avatar Dec 26 '18 13:12 dmitryduka

@dmitryduka Your proposal doesn't work because read_frame is executed by transfer_data_task; you can't call it separately.

aaugustin avatar Jul 07 '19 16:07 aaugustin

If the ability to receive individual fragments instead of messages must be provided on a per-message basis, there are several situations to consider:

  1. nothing received
  2. one message partially received
  3. at least one message fully received

I'm afraid the logic around _pop_message_waiter could get more complicated if it needs to handle all these situations.

Also, this will require switching from a message queue to a frame queue, which will open backwards compatibility questions.

aaugustin avatar Jul 07 '19 16:07 aaugustin

To handle streaming data would it be possible to do this on the message queue with out the finbit being set?

rsska avatar Aug 26 '19 22:08 rsska

Yes, that's what this issue is about — "fragmented messages" don't have the FIN bit set, except on the last frame.

aaugustin avatar Aug 27 '19 07:08 aaugustin

The new threading-based API supports this.

aaugustin avatar Apr 01 '23 12:04 aaugustin

The new threading-based API supports this.

Any plans of it to the asyncio-based API and/or the Sans API's?

shaohme avatar Nov 03 '23 14:11 shaohme

The plan for asyncio is #1332, ETA 1 to 3 years from now.

aaugustin avatar Nov 04 '23 20:11 aaugustin

It is de facto possible in the Sans-I/O API because that layer only knows about frames. It doesn't reassemble fragmented messages.

aaugustin avatar Nov 04 '23 20:11 aaugustin