ansar-connect

The ansar-connect library is for anyone developing networking software. That software might be a pair of client-server processes on a single host, a group of peer processes distributed around a LAN, or a large collection of processes distributed around the Internet. For the full range of potential target scenarios this library makes many aspects of networking easier while not compromising on sophistication. It also brings significant new capabilities.

A few highlights of the feature list include;

  • uniform messaging across multiple processes, multiple hosts and the Internet,

  • built-in public key cryptography,

  • automated management of network addresses,

  • support for mutiple instances of a networking product on the same physical network,

  • clear, concise and sophisticated network messaging.

Sending messages around networks is the core function of ansar-connect. It presents the simplest possible interface, accepting a message and a destination as arguments. It then discreetly takes care of technical issues such as marshaling, encoding, efficient network I/O and error handling. Refer to paragraphs below for a small but complete example of a client-server message exchange.

With ansar-connect it is possible to exchange messages between your development site and a remote weather station, or between a customer site and their mobile vehicle fleet. All of this can be achieved with little or no network administration (e.g. changing firewalls), and without regard to LAN infrastructure or public network providers (e.g. cellular networks). The only requirements are a Python environment and Internet connectivity at each end.

Encryption is as easy as enabling a flag when establishing a connection. A state-of-the-art encryption library is used to bring security to any selected area of your software.

Motivated by initiatives such as Zeroconf ansar-connect can sidestep the need for management of port numbers by using ephemeral ports. Combined with other techniques this makes it possible to run multiple instances of the same complex networking product, side-by-side. This has perhaps the most obvious value in development and testing but can equally benefit areas such as sales and training.

At the same time that this library extends the scope of networking, it never forgets how difficult the implementation and maintenance of networking software can be. Design goals included ease of use, code clarity and effective technical support.

Installation

ansar-connect can be installed from PyPI using pip;

$ cd <new-folder>
$ python3 -m venv .env
$ source .env/bin/activate
$ pip3 install ansar-connect

Features

  • Easy-to-use listen and connect,

  • fully automated sending and receiving of complex types (i.e. no marshaling or encoding),

  • direct support for arrays, vectors, sets, deques and maps,

  • support for user-defined types and enumerations,

  • a rich set of built-in types such as world time (i.e. datetime) and UUIDs,

  • support for graphs, e.g. linked lists and trees,

  • support for networking sessions,

  • support for networking FSMs,

  • support for multiple connections and multiple listens in a single process,

  • automated connection recovery with backoff and randomization,

  • extensive support for publish-subscribe networking.

For serialization ansar-connect uses ansar-encode, inheriting all the related data-handling sophistication from there. The ansar-create library is used for the internal asynchronous engine. Refer to the relevant documentation for details.

Note

For a bare minimum demonstration of messaging across the Internet, refer to this section.

A Very Quick Taste

ansar-connect has a broad and ambitious scope. At the same time it looks after the simplest networking ambitions with a clean interface and some nice automatic behaviour, the latter assisting with development and support activities. Under the hood all the capabilities of the library are based on the listen() and connect() pair of functions that appear in the following code samples.

A traditional, bare-bones server looks like;

import ansar.connect as ar

def server(self):
    ar.listen(self, ar.HostPort('127.0.0.1', 50101))

    m = self.select(ar.Listening, ar.NotListening, ar.Stop)
    if isinstance(m, ar.NotListening):
        return m
    elif isinstance(m, ar.Stop):
        return ar.Aborted()

    while True:
        m = self.select(ar.Enquiry, ar.Stop)
        if isinstance(m, ar.Stop):
            return ar.Aborted()

        self.reply(ar.Ack())    # Respond to the Enquiry message.

ar.bind(server)

if __name__ == '__main__':
    ar.create_object(server)

Save this code in the file server.py and run it with the command;

$ python3 server.py --debug-level=DEBUG

A control-c terminates the server when it is no longer needed. The matching client looks like this;

import ansar.connect as ar

def client(self):
    ar.connect(self, ar.HostPort('127.0.0.1', 50101))

    m = self.select(ar.Connected, ar.NotConnected, ar.Stop)
    if isinstance(m, ar.NotConnected):
        return m
    elif isinstance(m, ar.Stop):
        return ar.Aborted()

    self.reply(ar.Enquiry())    # Respond to the Connected message.

    m = self.select(ar.Ack, ar.Unknown, ar.Stop, seconds=3.0)
    if isinstance(m, ar.Stop):
        return ar.Aborted()
    elif isinstance(m, ar.SelectTimer):
        return ar.TimedOut(m)

    return m

ar.bind(client)

if __name__ == '__main__':
    ar.create_object(client)

Running the client (the omission of debugging is deliberate) looks like this;

$ python3 client.py
Ack()

There has been a successful exchange of Enquiry and Ack messages between the client and server processes. The create_object() library function places a simple text rendering of the return value from the client() object (i.e. m) on stdout. More information relating to connection establishment and message transfer is available in the logs.

The more curious may also attempt to run the client when the server is not active. Modifying the server to ignore the requests (i.e. comment out the reply() call) will elicit another example of automated error handling in the client.

Note

The Enquiry and Ack messages are pre-registered in the library and used here to simplify the code fragments. You can find an example of how to register your own custom messages here. The client() and server() objects are defined as functions for ease of reading but could equally be implemented as finite state machines. For an example of this style of operation look here. If you are unfamiliar with, or curious about asynchronous programming, you can find a solution to the Dining Philosophers problem here. This solution also uses FSMs.

Documentation

Documentation for ansar-connect covers three major areas. Part one is devoted to the traditional combination of listen() and connect() while the second part introduces the publish-subscribe model of networking. Further support for this model is provided in a series of guides.

The remainder of the documentation is reference material, including internal design and implementation details that may be significant to users.

Author

The ansar-connect library was developed by Scott Woods (scott.18.ansar@gmail.com). The library has evolved under the influence of several large projects and more recently has moved from C++ to Python.

License

The ansar-connect library is released under the MIT License.