wiki:Tutorials/oMF/tut3

Version 8 (modified by wontoniii, 10 years ago) ( diff )

Exercise 3: Socket Programming using New MobilityFirst NetAPI

Design/Setup

Objective:

In this exercise we will learn to write, compile, and run a simple content distribution application using MobilityFirst's new socket API. In particular we will focus on its Java release. We will then introduce a general view on MobilityFirst's native support for point to multi-point delivery services such as anycast and multicast to enable more flexible delivery options.

Pre-requisites

  • Experimenters are expected to have basic networking knowledge and familiarity with Linux OS and some of its tools (command line tools, ssh, etc.).
  • An ORBIT user account.
  • Some familiarity with the MobilityFirst terminology.

Deploy the Network

This tutorial assumes that a 4 nodes topology has been already established in one of the Orbit sandboxes or the grid:

No image "MFTurorialNetwork.png" attached to Tutorials/oMF

If not coming from exercise 1 follow these instructions on how to setup the topology. Running exercise 1 at least once before moving to exercise 2 is advised to understand the steps and software components involved.

Develop Sender and Receiver Applications with MF Socket API

As per the goal of the exercise, we will introduce the reader to the new MF Socket API. Two simple Java applications skeletons have been made available on the nodes. These applications consist of a sender, that takes as an input a file and transmit it to a receiver that once has received the complete file anwers back with an acknowledgement. Let's first analyze the sender code:

public static void main(String []argv){
        if(argv.length < 2){
            usage();
            return;
        }
        
        //The profile describes the nature of the communication that will follow and
        //  is used by the network stack to select the best end-to-end transport
        //For this application a 'basic' profile is selected providing only a message based
        //  transport with no added realiability on top of what offered by the network.
        String profile = "basic";
        GUID srcGUID = null;
        
        //A GUID class is used for name based communications
        //The destination of the fie has been passed as a parameter
        GUID dstGUID = new GUID(Integer.parseInt(argv[1]));
        //The source is optional. If a source is not specified, the default GUID of the device is used
        if(argv.length == 3) srcGUID = new GUID(Integer.parseInt(argv[2]));
        
        Path file = FileSystems.getDefault().getPath(argv[0]);
        
        //The JMFAPI object represents the socket and the API to interact with it
        JMFAPI sender = new JMFAPI();
        
        try{
            
            //The open call creates the communication socket and initializes the resources
            if(srcGUID!=null) sender.jmfopen(profile, srcGUID);
            else sender.jmfopen(profile);
            
            byte[] fileArray;
            try {
                fileArray = Files.readAllBytes(file);
            } catch (IOException e){
                System.out.println("ERROR");
                return;
            }
            System.out.println("Transferring a file of size " + fileArray.length);
            byte[] sizeArray = Utils.intToByteArray(fileArray.length);
            sender.jmfsend(sizeArray, 4, dstGUID);
            int sentBytes;
            
            byte[] tempArray;
            int ret, read = 0;
            int bytesToSend = fileArray.length;
            while(bytesToSend>1000000){
                tempArray = Arrays.copyOfRange(fileArray, 0, 999999);
                //Messages are sent up to 10MB at a time (which is the default buffer size for the socket)
                sentBytes = sender.jmfsend(tempArray,1000000, dstGUID);
                bytesToSend -= sentBytes;
                System.out.println("Transmitted " + sentBytes);
            }
            tempArray = Arrays.copyOfRange(fileArray, 0, bytesToSend - 1);
            sentBytes = sender.jmfsend(tempArray,bytesToSend, dstGUID);
            System.out.println("Transmitted " + sentBytes);
            
            //Receive the confirmation from the receiver
            //The first parameter is set to null but could be used to obtain the GUID of the message source
            sender.jmfrecv_blk(null,tempArray, 1000000);
            int receivedBytes = Utils.byteArrayToInt(tempArray, 0);
            System.out.println("The receiver received " + receivedBytes + " succesfully");
            
            //Close the socket and clear the resources
            sender.jmfclose();
            System.out.println("Transfer completed");
            
        } catch (JMFException e){
            //Exceptions related to events occured in the network protocol stack are defined as JMFException
            System.out.println(e.toString());
        }
    }

The receiver code is now presented:

public static void main(String []argv){
        //The profile describes the nature of the communication that will follow and
        //  is used by the network stack to select the best end-to-end transport
        //For this application a 'basic' profile is selected providing only a message based
        //  transport with no added realiability on top of what offered by the network.
        String scheme = "basic";
        
        GUID srcGUID = null;
        GUID senderGUID = new GUID();
        int i = 0;
        
        //A GUID class is used for name based communications
        //The source is optional. If a source is not specified, the default GUID of the device is used
        if(argv.length == 1) srcGUID = new GUID(Integer.parseInt(argv[0]));
        
        Path file = FileSystems.getDefault().getPath("temp.txt");
        try{
            Files.createFile(file);
        } catch(IOException e){
            try{
                Files.delete(file);
                Files.createFile(file);
            } catch(IOException e2){
                System.out.println(e2.toString());
                return;
            }
        }
        
        byte[] buf = new byte[1000000];
        int ret;
        JMFAPI receiver = new JMFAPI();
        try{
            if(srcGUID!=null) receiver.jmfopen(scheme, srcGUID);
            else receiver.jmfopen(scheme);
            
            //First message will include the size of the transfered file
            ret = receiver.jmfrecv_blk(senderGUID, buf, 1000000);
            int fileSize = Utils.byteArrayToInt(buf, 0);
            System.out.println("I will receive a file of size " + fileSize + " bytes from host with GUID " + senderGUID.getGUID());
            
            int total = 0;
            while(i < fileSize){
                ret = receiver.jmfrecv_blk(null, buf, 1000000);
                total+=ret;
                System.out.println("Received " + ret + " bytes");
                try{
                    Files.write(file, Arrays.copyOfRange(buf, 0, ret), StandardOpenOption.APPEND);
                } catch (IOException e){
                    System.out.println(e.toString());
                }
                i += ret;

            }
            
            //Send back an acknowledgement with the amount of bytes received
            byte[] answer = Utils.intToByteArray(total);
            receiver.jmfsend(answer,4, senderGUID);
            
            receiver.jmfclose();
        } catch (JMFException e){
            System.out.println(e.toString());
        }
        System.out.println("Transfer completed");
    }
}

While a very simple application a few concepts can be taken away from code just presented:

  • Communication profiling:
  • Named operations:

Execute

As in the previous tutorials, you will need to start the experiment via an OMF script. Download the script to the orbit console copying and pasting the following command in your terminal:

    wget www.winlab.rutgers.edu/~bronzino/downloads/orbit/exercise3.rb

Once the file has been downloaded, execute it with the following command:

    omf exec exercise3.rb

Once your experiment is showing you the following line:

    INFO exp: Request from Experiment Script: Wait for 10000s....

you can proceed with the execution of the applications. Using the previously opened consoles log in into the two host nodes (GUIDs 101 and 102) that will be used to run the simple 'mfping' application. In order to access a running Orbit node ssh into it as follow:

ssh root@nodex-y

Where x-y has to be replaced by the actual numbers identifying the node.

Once logged in, run on the node with GUID 102 the receiver component:

cd exercise3
java -cp .:jmfapi-1.0-SNAPSHOT.jar Receiver

where "-s" specifies that the host is running as server, "-m" specifies the source guid and "-o" the destination one

To run the mfping 'client' start on the client with GUID 101 the command:

cd exercise3
java -cp .:jmfapi-1.0-SNAPSHOT.jar Sender 10MB.dat 102

Where "-c" specifies the client is running and "-n" specifies the number of pings between the two nodes.

What's next

In this tutorial we only scratched the surface of what is possible to implement using the new Socket Network API. A few examples on what can be done:

  • Using multipoint delivery (e.g. multicast, anycast) through use of socket options on a per-operation base.
  • Content based communication profiles and operations (e.g. get).
  • Use of a mobility manager with support for simple migration policies, e.g., “use WiFi whenever available”.
  • Interact with the Global Name Service for name to addresses management.

Finish

Once the application has successfully completed its task, follow these steps to complete the experiments:

  • On the grid's console running the experiment script, interrupt the experiment using the Ctrl-C key combination.

This will stop all the applications and will conclude the experiment.

References

For more information regarding the MobilityFirst project, visit the project page: http://mobilityfirst.winlab.rutgers.edu/

For more information regarding the prototype design and updated status, visit the wiki page: https://mobilityfirst.orbit-lab.org/

Note: See TracWiki for help on using the wiki.