"Elegant" message passing from single UDP socket to multiple tokio::tasks

Dear Rust community,

I have been programming Rust for almost 9 months. This is my first post ;).

Maybe you can help me with the following problem statement:

Via a single tokio::udp socket I am receiving messages, which are going to be distributed further on to several tokio::tasks.

To be more precise: Each message contains a single service, which is handled by exactly one of the spawned tokio::tasks. A Json defines all relevant services for the receiver.

I am now stuck which of Tokio's channel primitives I should use:

  • My first idea was to use tokio::sync::watch (reflecting a single-producer, multi-consumer). But after a closer look this is not fully appropriate for that scenario: Now every message from the socket is distributed to all consumers / tokio::tasks, although the message is only relevant for a single tokio::task. Also what happens if the network packets are received in a much higher frequency that the watch channel can distribute (slow receiver)?

  • My second approach was to just use a dedicated oneshot channel per service (and it's corresponding tokio::task). Whenever a message comes in via the socket, the service type is determined and the appropriate oneshot channel is selected. This would reflect the 1:1 communication more precisely, but now I have to create (potentially) a lot of channels. Isn't that too inefficient?

Are there any other solution?

Thanks in advance!

Greetings from Germany!

A oneshot channel? Do you only need to send one message per service?

Too little/vague info.
From all I read you may be better spawning a task for each received message. I have no idea what you intend a service to receiving a single message to be doing.

Thanks for answering.

Some clarifications: The "services", which I mentioned, will each get several messages back-to-back (not only a single message and then the service is done).

So a channel with a buffer is needed (definitely later on). I mentioned the tokio::oneshot, because it suited the 1:1 communication scenario and I thought for getting started the single value "capacity" is enough.

I would probably try to model your services using the actor pattern, spawning a task per service. The udp socket task can then store a list or hash map of actor handles that it can use to send messages to the services. I would use a tokio::sync::mpsc channel.

Thank you Alice!

Your article is perfect and solved my questions.

Thanks for the quick reply!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.