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

The University for the Information Society