Skip to content

Commit c81a5d1

Browse files
[DOCUMENTATION] Improved FAQ some more (- WIP #425 -)
Additions with file docs/INSTALL.md: * initial draft of INSTALL guide Additions with file docs/SECURITY.md: * minimal Draft for SECURITY Changes in file docs/FAQ.md: * various improvements
1 parent 1e90003 commit c81a5d1

File tree

3 files changed

+301
-80
lines changed

3 files changed

+301
-80
lines changed

docs/FAQ.md

Lines changed: 222 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -4,155 +4,297 @@
44

55
```{toctree}
66
:maxdepth: 3
7+
:Name: Frequently Asked Questions
78
8-
[Code of Conduct](https://github.com/reactive-firewall/multicast/blob/master/.github/CODE_OF_CONDUCT.md)
9-
[Contributing](https://github.com/reactive-firewall/multicast/blob/master/.github/CONTRIBUTING.md)
9+
[Code of Conduct](https://github.com/reactive-firewall/multicast/tree/HEAD/.github/CODE_OF_CONDUCT.md)
10+
[Contributing](https://github.com/reactive-firewall/multicast/tree/HEAD/.github/CONTRIBUTING.md)
1011
```
1112

1213
### How do I get this running?
1314

14-
(assuming python3 is set up and installed)
15+
To configure your environment for developing with the multicast library, follow the steps in the
16+
[Install Guide](https://github.com/reactive-firewall/multicast/tree/HEAD/docs/INSTALL.md).
17+
Key steps include:
1518

16-
```bash
17-
# cd /MY-AWESOME-DEV-PATH
18-
# Retrieve a copy of the project, for example clone the source repository
19-
git clone https://github.com/reactive-firewall/multicast.git multicast && cd ./multicast
19+
1. Ensuring you have a supported version of Python installed.
20+
2. use pip to install
21+
3.
22+
| _in `Python`_ | _in `bash`_ |
23+
|---------------|-------------|
24+
| `import multicast` | `python3 -m multicast --help` |
25+
26+
### How do I use this `multicast` to receive some UDP multicast?
2027

21-
# Make sure you are using stable if in production
22-
git checkout stable
28+
With `multicast` installed and set up, this guide will assume you want to listen to multicast
29+
group `224.0.0.1` on the UDP port `59595`.
2330

24-
# Optionally check your environment is compatible
25-
# make clean ; make test ; make clean ;
31+
#### _Prototype in `bash`_
2632

27-
# Install the module
28-
make install ;
33+
This command will allow you to quickly prototype and test receiving multicast messages without
34+
needing to write a full Python script. Once you confirm that the command works as expected, you
35+
can then proceed to implement a more advanced solution in Python as necessary.
2936

30-
# Use the module
31-
python3 -m multicast --help ;
37+
```bash
38+
python3 -m multicast --daemon --use-std HEAR --port 59595 --group 224.0.0.1
3239
```
3340

34-
#### DONE
41+
| Explanation of the Command-Line Options | |
42+
|---------------------|---------------------|
43+
| `--daemon` | This option runs the multicast listener as a background daemon. |
44+
| `--use-std` | This specifies the action to take when any output is produced. In this case, it uses the standard output to print received messages instead of the default to just log messages. |
45+
| `HEAR` | This specifies the action to take. In this case, it will _receive_ multicast. |
46+
| `--port 59595` | This sets the UDP port number to `59595`, which is used to identify/filter the multicast messages that will be accepted. |
47+
| `--group 224.0.0.1` | This specifies the multicast group address to join. You can replace `224.0.0.1` with your desired multicast group address. |
3548

36-
If all went well, `multicast` is now installed and working :tada:
49+
##### Steps to Run
3750

38-
### How do I use this `multicast` to receive some UDP multicast?
51+
1. Open your terminal.
52+
2. Ensure you have the multicast module installed and accessible.
53+
3. Run the command above, adjusting the port and group as needed for your specific use case.
3954

40-
(assuming `multicast` is set up, installed and you want to listen on 0.0.0.0)
55+
Most users will want to stick to using `HEAR` when receiving multicast from the CLI. Alternatively,
56+
users can use the ephemeral `RECV` _(by omitting the `--daemon` flag)_ to receive individual UDP
57+
messages, no more than one message at a time.
4158

42-
```bash
43-
# cd /MY-AWESOME-DEV-PATH
44-
python3 -m multicast --daemon --use-std HEAR --port 59595 --group 224.0.0.1
45-
```
59+
> [!TIP]
60+
> Caveat: `RECV` is much more useful if actually used in a loop, for example:
61+
>
62+
> ```bash
63+
> while true ; do # until user Ctrl+C interrupts
64+
> python3 -m multicast --use-std RECV --port 59595 --group 224.0.0.1 --groups 224.0.0.1
65+
> done
66+
> ```
4667
47-
Most users will want to stick to using `HEAR` when receiving multicast from the CLI. Alternatively,
48-
users can use `RECV` _(by omitting the `--daemon` flag)_ to receive individual UDP
49-
messages, no more than one at a time.
68+
#### _Develop in `Python`_
5069
51-
> [!IMPORTANT]
52-
> Caveat: `RECV` is much more useful if actually used in a loop like:
5370
54-
```bash
55-
# cd /MY-AWESOME-DEV-PATH
56-
while true ; do # until user Ctrl+C interrupts
57-
python3 -m multicast --use-std RECV --port 59595 --group 224.0.0.1 --groups 224.0.0.1
58-
done
59-
```
6071
6172
### How do I use this to send UDP Multicast?
6273
63-
(assuming `multicast` is set up and installed)
74+
With `multicast` installed and set up, this guide will assume you want to send a message to
75+
multicast group `224.0.0.1` on the UDP port `59595`.
76+
77+
#### _Prototype in `bash`_
6478
6579
```bash
66-
# cd /MY-AWESOME-DEV-PATH
6780
python3 -m multicast SAY --group 224.0.0.1 --port 59595 --message "Hello World!"
6881
```
6982
70-
### What is the basic API via python (instead of bash like above)?
83+
| Explanation of the Command-Line Options | |
84+
|---------------------|---------------------|
85+
| `SAY` | This specifies the action to take. In this case, it will _transmit_ multicast. |
86+
| `--group 224.0.0.1` | This specifies the multicast group address to transmit messages to. You can replace `224.0.0.1` with your desired multicast group address. |
87+
| `--port 59595` | This sets the UDP port number to `59595`, which is used by other members of the multicast group to help identify/filter the multicast messages to accept. |
88+
| `--message` | This specifies the rest of the input is to be the message to transmit. |
89+
| `"Hello World!"` | This specifies the multicast message content to _transmit_. In this case, it is the greeting "Hello World!" |
90+
91+
##### Steps to Run
92+
93+
1. Open your terminal.
94+
2. Ensure you have the multicast module installed and accessible.
95+
3. Run the command above, adjusting the message, port and group as needed for your specific use case.
96+
97+
This command will allow you to quickly prototype sending multicast messages without needing to
98+
write a full Python script. You can test the sending functionality alongside the receiving
99+
functionality to ensure that messages are being transmitted and received correctly.
100+
101+
### What is the basic `multicast` Python API?
71102

72103
> [!WARNING]
73-
> Caveat: this module is still a BETA
74-
[Here is how it is tested right now](https://github.com/reactive-firewall/multicast/blob/389c93eb86e012a38edb88b3b81c7d4aa55e843a/tests/test_hear_cleanup.py#L54C2-L96C43)
104+
> Caveat: this example is still prototype focused, and should be considered a minimal
105+
> implementation (e.g., lacks useful input validation, lacks error handling, etc.)
106+
107+
```python3
108+
# imports
109+
from multiprocessing import Process as Process
110+
import multicast
111+
import random # for random port
112+
113+
# Multicast group address and port
114+
MCAST_GRP = "224.0.0.1" # Replace with your multicast group address (use IPv4 dotted notation)
115+
MCAST_PORT = int(random.SystemRandom().randint(49152, 65535)) # Replace with your multicast port
116+
117+
# Other important settings (Non-Multicast)
118+
# Multicast does not care about the host IP, but the UDP protocol layer of the Python socket does
119+
# There are 3 logical choices for the vast majority of users:
120+
# 1. '0.0.0.0' for Promiscuous mode (Usually needs privileges to use on most Operating Systems)
121+
# 2. The actual interface IPv4 dot notation address for unprivileged mode
122+
# 3. MCAST_GRP value, Linux and MacOS implementations can let the system choose by passing the
123+
# MCAST_GRP to the Python socket.bind operation (handled by multicast.skt when missing Host IP)
124+
# Windows users must use option 1 or 2 for now.
125+
# This address is per socket (e.g., can be chosen per socket even if on a single interface)
126+
# HOST_BIND_IP = "0.0.0.0"
127+
128+
# Options for multicast listener
129+
listener_options = {
130+
"is_daemon": True, # bool: enable daemon mode
131+
"port": MCAST_PORT, # int: UDP port for multicast
132+
"group": MCAST_GRP # str: multicast group address (use IPv4 dotted notation)
133+
}
134+
135+
# Create a multicast listener
136+
listener = multicast.hear.McastHEAR()
137+
138+
# create a separate process for the listener
139+
p = Process(
140+
target=listener,
141+
name="HEAR", kwargs=listener_options
142+
)
143+
p.daemon = listener_options["is_daemon"]
144+
p.start()
145+
146+
# ... use CTL+C (or signal 2) to shutdown the server 'p'
147+
```
148+
149+
Low-level with example handler:
75150

76151
```python3
152+
# imports
77153
import multicast
78154
import random # for random port
79155

80-
# set up some stuff
81-
_fixture_PORT_arg = int(random.SystemRandom().randint(49152, 65535))
82-
_fixture_mcast_GRP_arg = "224.0.0.1" # only use dotted notation for multicast group addresses
83-
_fixture_host_BIND_arg = "224.0.0.1"
156+
# Multicast group address and port
157+
MCAST_GRP = "224.0.0.1" # Replace with your multicast group address (use IPv4 dotted notation)
158+
MCAST_PORT = int(random.SystemRandom().randint(49152, 65535)) # Replace with your multicast port
159+
160+
# Other important settings (Non-Multicast)
161+
# Multicast does not care about the host IP, but the UDP protocol layer of the Python socket does
162+
# There are 3 logical choices for the vast majority of users:
163+
# 1. '0.0.0.0' for Promiscuous mode (Usually needs privileges to use on most Operating Systems)
164+
# 2. The actual interface IPv4 dot notation address for unprivileged mode
165+
# 3. MCAST_GRP value, Linux and MacOS implementations can let the system choose by passing the
166+
# MCAST_GRP to the Python socket.bind operation (handled by multicast.skt when missing Host IP)
167+
# Windows users must use option 1 or 2 for now.
168+
# This address is per socket (e.g., can be chosen per socket even if on a single interface)
169+
HOST_BIND_IP = MCAST_GRP
170+
171+
# Options for multicast listener
172+
listener_options = {
173+
"is_daemon": False, # bool: enable/disable daemon mode
174+
"groups": [MCAST_GRP], # list[str]: multicast group addresses (use IPv4 dotted notation list)
175+
"port": MCAST_PORT, # int: UDP port for multicast
176+
"iface": None, # str: System specific interface name, or None to let system choose
177+
"bind": HOST_BIND_IP, # str: interface IP address (unnecessary; only included for completeness)
178+
"group": MCAST_GRP # str: primary multicast group address (use IPv4 dotted notation)
179+
}
180+
181+
# Example setup for Low-Level use-case
182+
# Define a decorator to loop until able to print a string result of enough length
183+
import functools
84184

85-
# spawn a listening proc
86185

87186
def printLoopStub(func):
88-
for i in range( 0, 5 ):
89-
print( str( func() ) )
187+
@functools.wraps(func)
188+
def wrapper(*args, **kwargs):
189+
while True:
190+
# cache function result
191+
cache = func(*args, **kwargs)
192+
if cache and len(cache) > 1:
193+
print( str( cache ) )
194+
break
195+
elif not cache:
196+
continue
197+
else:
198+
print("Result is too short.")
199+
return wrapper
200+
201+
202+
# Example low-level handler
203+
# Define a decorated handler to only return successfully received messages
204+
90205

91206
@printLoopStub
92207
def inputHandler():
93-
test_RCEV = multicast.recv.McastRECV()
208+
# Create an ephemeral multicast receiver
209+
receiver = multicast.recv.McastRECV()
210+
# create an empty default string
94211
out_string = str()
95-
(didWork, buffer_string) = test_RCEV.doStep(
96-
groups=[_fixture_mcast_GRP_arg], port=_fixture_PORT_arg,
97-
iface=None, group=_fixture_host_BIND_arg
212+
# try to receive some multicast messages
213+
(didWork, buffer_string) = receiver(
214+
**listener_options
98215
)
216+
# check the result and "handle" if successful
99217
if didWork:
100218
out_string += buffer_string
219+
del receiver # optionally cleanup receiver beforehand
101220
return out_string
102221

222+
223+
# create the actual handler instance
103224
inputHandler()
104225

105-
# alternatively listen as a server
106-
# import multicast # if not already done.
226+
```
227+
228+
_and elsewhere (e.g., in another module or even on another system); an example for the sender API:_
229+
230+
```python3
231+
# imports
107232
from multiprocessing import Process as Process
233+
import multicast
108234

109-
_fixture_HEAR_kwargs = {
110-
"is_daemon": True,
111-
"port": _fixture_PORT_arg,
112-
"group": _fixture_host_BIND_arg
113-
}
114-
p = Process(
115-
target=multicast.hear.McastHEAR().doStep,
116-
name="HEAR", kwargs=_fixture_HEAR_kwargs
117-
)
118-
p.daemon = _fixture_HEAR_kwargs["is_daemon"]
119-
p.start()
235+
# Multicast group address and port
236+
MCAST_GRP = "224.0.0.1" # Replace with your multicast group address (use IPv4 dotted notation)
237+
MCAST_PORT = int(59595) # Replace with your multicast port (use the same port as the listeners)
120238

121-
# ... use CTL+C (or signal 2) to shutdown the server 'p'
122-
```
239+
# Other important settings (Non-Multicast)
240+
# Multicast does not care about the host IP, but the UDP protocol layer of the Python socket does
241+
# The sender will default to letting the system choose
242+
# HOST_BIND_IP = "0.0.0.0"
123243

124-
_and elsewhere (like another function or even module) for the sender:_
244+
# Options for multicast sender
245+
sender_options = {
246+
"port": MCAST_PORT, # int: UDP port for multicast
247+
"group": MCAST_GRP, # str: multicast group address (use IPv4 dotted notation)
248+
"data": "Default listener only knows: STOP" # str: message content to try to _transmit_
249+
}
125250

126-
```python3
251+
# Create an ephemeral multicast sender
252+
sender = multicast.send.McastSAY()
127253

128-
# assuming already did 'import multicast as multicast'
254+
# create a separate process for the sender
255+
p = Process(
256+
target=sender,
257+
name="SAY", kwargs=sender_options
258+
)
259+
p.daemon = False # sender should not be a daemon
129260

130-
_fixture_SAY_args = [
131-
"--port", _fixture_PORT_arg,
132-
"--group", _fixture_mcast_GRP_arg,
133-
"--message", "'test message'"
134-
]
135261
try:
136-
multicast.__main__.McastDispatch().doStep(["SAY", _fixture_SAY_args])
137-
# Hint: use a loop to repeat or different arguments to vary message.
262+
p.start()
138263
except Exception as baton:
139-
p.join()
264+
p.join() # good practice to handle clean up
140265
raise RuntimeError("multicast seems to have failed.") from baton # re-raise
141266
finally:
142267
# clean up some stuff
143268
if p:
144269
p.join() # if not already handled don't forget to join the process and other overhead
145270
# hint: if you use a loop and need to know the exit code
146271
didWork = (p is not None and int(p.exitcode) <= int(0)) # e.g. check for success
272+
147273
```
148274

149275
> [!WARNING]
150-
> Caveat: the above examples assume the reader is knowledgeable about general `IPC` theory and
151-
> the standard python `multiprocessing` module and its use.
276+
> Caveat: the above examples assume the reader is knowledgeable about general
277+
> interprocess communication theory and the standard python `multiprocessing` module and its use.
278+
> Together these examples demonstrate a trivial message passing IPC using multicast python sockets.
152279
153280
Here is a
154281
[more CLI focused way to test](https://github.com/reactive-firewall/multicast/blob/389c93eb86e012a38edb88b3b81c7d4aa55e843a/tests/test_usage.py#L385C2-L432C43)
155-
as another example of how to use the module.
282+
as another trivial example of how to use the module.
283+
284+
### How do I run and interpret the test suite for this project?
285+
286+
To run the test suite, follow the instructions in the [Testing Guide](https://github.com/reactive-firewall/multicast/tree/HEAD/docs/Testing.md).
287+
288+
The guide explains test organization, and how to run tests outside CI/CD.
289+
290+
### How is continuous integration (CI) set up for this repository?
291+
292+
CI is configured as described in the [CI Guide](https://github.com/reactive-firewall/multicast/tree/HEAD/docs/CI.md).
293+
Key points:
294+
295+
Automated builds and tests are run via GitHub Actions. Each pull request is tested for
296+
compatibility and code quality. The guide details the CI workflow files, environment variables,
297+
and what to expect when contributing changes.
156298

157299
### What are the defaults?
158300

@@ -170,7 +312,7 @@ From the
170312
#### Default Multicast Bind Address
171313

172314
> [!NOTE]
173-
> The **default** multicast bind address is the **default** group. This is efectivly `224.0.0.1`.
315+
> The **default** multicast bind address is the **default** group. This is effectively `224.0.0.1`.
174316
175317
#### Default TTL
176318

0 commit comments

Comments
 (0)