Skip to content

Session

John Smith edited this page Apr 26, 2020 · 1 revision

WIKI Home -> Session API docs

You will need an instance of NKNClient

NKNClient client = new NKNClient(new Identity("Name", Wallet.createNew()));
client.start();

As you can see, the client requires Identity which is built from a friendly name, whatever you like (it may be null) and instance of Wallet which you plan to use for this particular instance. Let's just generate a new one.

Session tunnel is a fully duplex reliable protocol, that uses multiple NKN clients to connect both parties together and transmits data using all connections in a load-balancing manner. It handles congestion control, packet drop, and re-sending, buffering, and order of packets of data.

For two sides to establish a session tunnel, one side must be in "server mode", which means awaiting an incoming connection and the other must dial this connection. After a session has been established everything is the same for both sides.

Connection awaiting side

Assuming we already have a started client instance, let's set a callback for incoming sessions:

clientB.sessionProtocol().onSessionRequest(s -> {
    // Prepare session, if it gets established
    s.onSessionEstablished() {
       // Do something, send or receive data
       // This method shouldnt block, which means unless you are just setting a flag in your code somewhere, create a new thread
    };
    s.onSessionBrokenTunnel(() -> {
        LOG.warn("Session tunnel broke");
    });


    // If incoming connection is from a whitelist of allowed nodes,
    if (s.remoteIdentifier.equals("Friend.NKNaddress")) {
        return true; // Accept the session
    } else {
        return false; // Drop the connection attempt
    }

})

Connection dialing side

To dial a session, call:

Session s = client.sessionProtocol().dialSession(targetFullIdentifier);

and set session callbacks, same as before:

    // Prepare session, if it gets established
    s.onSessionEstablished() {
       // Do something, send or receive data
       // This method shouldnt block, which means unless you are just setting a flag in your code somewhere, create a new thread
    };
    s.onSessionBrokenTunnel(() -> {
        LOG.warn("Session tunnel broke");
    });

Shared

To use the (established) session, use get SessionInputStream and SessionOutputStream using:

final SessionInputStream nknIn = session.getInputStream();
final SessionOutputStream nknOut = session.getOutputStream();

On top of implementing standard java stream behavior, session streams provide additional methods. Most important is

nknOut.getUnconfirmedSentBytesCount();

which returns a number of bytes that have been written to the send queue, but not acknowledged as received from the other side. For any reason, let it be a slow network connection, full buffers, or dropped ACK packet.

More options

You can use sessions with custom parameters, of course. Here is a list:

  • Number of multiclients used
  • PreferredMtu
  • PreferredWinSize

Session param value used is minimum value of dialing and awaiting side. To set these parameters as awaiting side, use methods:

client.sessionProtocol().setIncomingPreferredMulticlients(8); // Default 4
client.sessionProtocol().setIncomingPreferredMtu(512); // In bytes, Default is 1024
client.sessionProtocol().setIncomingPreferredWinSize(8 * 1024 * 1024); // In bytes, default is 4K

as for dialing session, use dialSession overload

client.sessionProtocol().dialSession(String destinationFullIdentifier, int multiclients, String[] targetPrefixes, int maxMtu, int maxWindowSize)

targetPrefixes is a String array such as __0__, __1__ which are the prefixes of multiclient on which the server side is listening. Pass null for default. Default are __${i}__ for i in range 0 to multiclient count. Listening side listens for a connection on empty prefix as well, but doesn't use it for actual communication.