Skip to content

Commit 7c2ef66

Browse files
committed
documentation
1 parent d0b46b5 commit 7c2ef66

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

README.md

+131
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,134 @@ You can find several examples (client and server files) contained in the **Tests
2525
cd Tests\example1
2626
python3 server.py network.txt
2727
```
28+
Below you can find another example (example3) with some comments to help you become
29+
familiar with the framework.
30+
## Server
31+
32+
```python
33+
import networkx as nx
34+
import sys
35+
import Nodes.utils as utils
36+
import Nodes.initializers as initializers
37+
import os
38+
39+
#create any graph you like with networkx
40+
G = nx.erdos_renyi_graph(7, 0.5, seed=1, directed=False)
41+
42+
#print some metrics of interest
43+
n = G.number_of_nodes()
44+
m = G.number_of_edges()
45+
print(f"Nodes: {n}")
46+
print(f"Edges: {m}")
47+
print(f"Expected n. of messages: {(4*m)-(2*n)+2}")
48+
49+
#specify the path of the client absolute path
50+
client = os.path.abspath("./client.py")
51+
52+
#create the initializer object
53+
init = initializers.Initializer(client, "localhost", 65000, G, shell=False)
54+
55+
#wakeup node with ID=5
56+
init.wakeup(5)
57+
58+
#wait for protocol termination
59+
init.wait_for_termination()
60+
61+
#wait for messages containing total messages used during the protocol.
62+
init.wait_for_number_of_messages()
63+
```
64+
65+
## Client
66+
Here's an example client.py file. In this case, we want to create a node running the **Shout** protocol, which is alredy implemented in the **Protocols** package. Alternatively, you can define your custom protocol directly in the client.py file for convenience.
67+
68+
```python
69+
import sys
70+
from Nodes.Nodes.Node import Node
71+
from Nodes.Protocols.Shout import Shout
72+
if len(sys.argv) != 4:
73+
raise ValueError('Please provide HOST, initializer PORT and local PORT NUMBER.')
74+
NODE = Node(sys.argv[1], int(sys.argv[2]), int(sys.argv[3]))
75+
76+
#create the protocol object
77+
proto = Shout(NODE)
78+
79+
#run the protocol
80+
proto.run()
81+
```
82+
83+
## Protocol
84+
This is a possibile implementation of the Shout protocol, used to create a spanning tree in a undirected graph in a distributed way. As you can see, it is similar to pseudo-code.
85+
To create your custom protocol, always override these 3 methods:
86+
87+
- ```setup()```: setup procedure that each node executes at the beginning of the protocol. It is usefull to initialize variables or start parallel threads (see example5);
88+
89+
- ```handle_message()```: this method should be the core of the protocol. You have to specify for each possibile combination of state and message what the node should do. Remember that you can find some useful tokens in the ```Nodes.const``` package to avoid typos in strings.
90+
When the node has locally terminated the computation, just return ```True```.
91+
92+
- ```cleanup()```: you can optionally override this method to send extra information or log variables at the end of the protocol. In this case, we send the total number of messages sent by the node during the computation.
93+
94+
95+
```python
96+
from Nodes.Protocols.Protocol import Protocol
97+
from Nodes.messages import Message
98+
from Nodes.const import Command, State
99+
from Nodes.Nodes.Node import Node
100+
101+
class Shout(Protocol):
102+
def __init__(self, node: Node):
103+
super().__init__(node)
104+
105+
def setup(self):
106+
self.state = State.IDLE
107+
self.counter = None
108+
self.parent = None
109+
self.tree_neigs = set()
110+
111+
def handle_message(self, message: Message) -> bool:
112+
assert message.command != Command.START_AT, "This protocol supports only 1 initiator."
113+
if self.state == State.IDLE:
114+
if message.command == Command.WAKEUP:
115+
self.node.log("I am the root.")
116+
self.counter = 0
117+
self.state = State.ACTIVE
118+
self.node.send_to_all(Message(Command.Q, self.node.id))
119+
if message.command == Command.Q:
120+
self.node.log("I am a child.")
121+
self.parent = message.sender
122+
self.tree_neigs.add(message.sender)
123+
self.counter = 1
124+
self.node.send_to(Message(Command.YES, self.node.id), self.parent)
125+
if self.counter == len(self.node.get_neighbors()):
126+
self.state = State.DONE
127+
self.node.log("Computation Done.")
128+
self.node.log(str(self.tree_neigs))
129+
self.node.log(str(self.parent))
130+
return True
131+
else:
132+
self.node.send_to_all_except(message.sender, Message(Command.Q, self.node.id))
133+
self.state = State.ACTIVE
134+
elif self.state == State.ACTIVE:
135+
if message.command == Command.Q:
136+
self.node.send_to(Message(Command.NO, self.node.id), message.sender)
137+
if message.command == Command.YES:
138+
self.tree_neigs.add(message.sender)
139+
self.counter += 1
140+
if self.counter == len(self.node.get_neighbors()):
141+
self.state = State.DONE
142+
self.node.log("Computation Done.")
143+
self.node.log(str(self.tree_neigs))
144+
self.node.log(str(self.parent))
145+
return True
146+
if message.command == Command.NO:
147+
self.counter += 1
148+
if self.counter == len(self.node.get_neighbors()):
149+
self.state = State.DONE
150+
self.node.log("Computation Done.")
151+
self.node.log(str(self.tree_neigs))
152+
self.node.log(str(self.parent))
153+
return True
154+
155+
def cleanup(self):
156+
super().cleanup()
157+
self.node.send_total_messages()
158+
```

0 commit comments

Comments
 (0)