Application programming interface
We’ve already seen how to control the network using the GUI and how to start with an initial graph.
In some cases you may need an more complex simulation than an initial graph but still want to automate it. For such cases you can use the NetSimLan API. Start you graph example without a graph file but open a TCP port for the API: netsimlan grid -a 5000.
To interact with the API, you can use it by hand as a command-line interface, as we’ll do here.
With Linux open a terminal and type in nc localhost 5000,
with Windows you can use PuTTY to open a connection to localhost, port 5000 as connection type: raw.
For security it’s only possible to connect to the API from the same computer the simulation runs on.
You see a blank screen. Type in help
to see all available commands. Commands are line-based, so you need to just press enter afterwards.
Answers from the API always start with + for success or - for failures. Successes are followed by the answer and failures are followed by a description. Answers with more than one line start with + list begin and end with + list end, the lines between don’t have a leading +.
All right, let’s find out which types our program has. Type in types
. You see, we only have “gridNode” as we defined in the source code.
Let’s create a node. Type in new gridNode mynode
, where “mynode” is an arbitrary name. Note this names can’t include spaces, but you can use underscores instead.
You see, you get the node id as answer. To interact with a node the API always uses the node id.
Repeat the command until you have created 10 nodes.
Now you can start the nodes using start 1
, start 2
etc. The number always is a node id to identify the node to start.
Let’s link this 10 nodes as in the grid but leave node 8 out.
To do so, use link 1 2
, link 2 1
, link 1 6
, link 6 1
, link 2 3
, …
Have a look at the GUI at node 7’s stored data. The route to 9 is via node 2. When you now add 8 to the graph, you see a new route is established. Use the same “link” command to do so: link 7 8
, link 8 9
, link 3 8
and inverse.
Let node 7 send a message to 9: Therefor you can look up the functions, 7 offers: functions 7, that are the functions implemented in our code. Use the message function to say “hello”: call 7 message hello 9
, again strings can’t include spaces. Spaces are reserved to separate parameters.
You can see the message arrives at 9 in the NetSimLan simulation.
Please be aware our example has the synchronization model from last chapter, so node 9 won’t timeout anymore until every node got a message.
You can also set a node asleep or kill it. For example use for node 8 sleep 8
or kill 8
.
To disable autolayouting you can use autolayout off
before you create the nodes and create them with more parameter for example using new gridNode mynode semisynchron 2 3
, where 2 is the coordinate in the first and 3 the coordinate in the second dimension of the visualization.
It’s also possible to enable displaying implicit edges using showimplict on
.
When you are done, you can close the connection to the API using exit
. Of course you can open a new connection again.
Of cause in your studies you don’t need to do this by hand, but you may use you favorite programming language as long as it offers sockets. Most modern languages for general purpose do so, like C, Java, Python and so on.
Example in python
An complete example for python may looks as follows. Here we build a grid step by step. You can see the point in time the messages which messages arrive at which part of the graph. This works automatically because of the automated message seinging from last chapter.
#!/usr/bin/env python3
import socket
import time
import sys
PORT = 5000 # The port used for the API
SIZE = 5 # as in our grid example
def raw_api_query(reader, writer, command):
# send command
writer.write(str(command) + "\n")
writer.flush()
# read answer and build list
line = reader.readline().strip('\n')
ans = []
# print error and exit if command not successful
if line == '' or line[0] != "+":
print("error: " + command + " returned " + str(line),
file=sys.stderr)
raise RuntimeError(str(line))
if line == '+ list begin':
# multi line answer
while line != '+ list end':
line = reader.readline().strip('\n')
if line != '' and line != '+ list end':
ans.append(line)
else:
# single line answer, skip leading plus
ans = line.split(' ')[1:]
return ans
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(('127.0.0.1', PORT))
with s.makefile(mode = 'r') as r, \
s.makefile(mode = 'w') as w:
# get types
types = raw_api_query(r, w, "types")
# create nodes of each type and store id
ids = []
for i in range(SIZE ** 2):
for t in types:
ans = raw_api_query(r, w, "new " + t + " myNode")
ids.append(ans[1])
# start nodes
for i in ids:
raw_api_query(r, w, "start " + i)
# every node sends a message to itself
for i in ids:
raw_api_query(r, w,
"call " + i + " message self_message " + i)
# establish first dimension of connections
for j in range(SIZE - 1):
for i in range(SIZE):
node1 = ids[i * SIZE + j]
node2 = ids[i * SIZE + j + 1]
raw_api_query(r, w, "link " + node1 + " " + node2)
raw_api_query(r, w, "link " + node2 + " " + node1)
# establish second dimension of connections with delay
for j in range(SIZE):
for i in range(SIZE - 1):
time.sleep(2)
node1 = ids[i * SIZE + j]
node2 = ids[(i+1) * SIZE + j]
raw_api_query(r, w, "link " + node1 + " " + node2)
raw_api_query(r, w, "link " + node2 + " " + node1)
# close connection
raw_api_query(r, w, "exit")
Previous: Advanced synchronization