Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support receiving fragmented messages without reassembly #479

Closed
aaugustin opened this issue Sep 23, 2018 · 11 comments
Closed

Support receiving fragmented messages without reassembly #479

aaugustin opened this issue Sep 23, 2018 · 11 comments

Comments

@aaugustin
Copy link
Member

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.

@lgrahl
Copy link
Collaborator

lgrahl commented Oct 25, 2018

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.

@dmitryduka
Copy link

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!

@aaugustin
Copy link
Member Author

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

@aaugustin
Copy link
Member Author

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.

@rsska
Copy link

rsska commented Aug 26, 2019

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

@aaugustin
Copy link
Member Author

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

@aaugustin
Copy link
Member Author

The new threading-based API supports this.

@shaohme
Copy link

shaohme commented Nov 3, 2023

The new threading-based API supports this.

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

@aaugustin
Copy link
Member Author

aaugustin commented Nov 4, 2023

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

@aaugustin
Copy link
Member Author

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
Copy link
Member Author

The new asyncio API, which provides this functionality, is now merged in the main branch (#1332).

The API is:

async for fragment in websocket.recv_streaming():
    ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants