Skip to content
Phil edited this page Feb 20, 2018 · 27 revisions

This document is for version 1.1.18+

Table of Contents:

The Vaser API and reference catalog can be found here.

Important: Please look at my other project VaserChat for a live vaser demo application!

Click on this link for a live demo: VaserChatv1.1.7.zip or ClickOnce setup.exe App

VaserChat Login

VaserChat Main Form

New Features:

  • Event based communication
  • added “OnEmptyBuffer” event on links
  • QoS packet priority
  • “Portal.Finalize()” is now obsolete
  • Added packet dispacher
  • Added Xamarin iOS Support
  • Added NetCore Support
  • Added Unity Support

Planned Features:

  • a better wikisite
  • the release of the file transfer and content delivery library

Overview of vaser:

how vaser works

Using directives:

using Vaser; // for normal networking usage
using Vaser.OON; // advanced functionality for request/response pattern and data channeling
using Vaser.ConnectionSettings; // contains the connection settings classes

Build a container:

// Build your container for transmitting your data 
// One message is limited to 65000 bytes
// Note that your container needs an ID for identifying which one is used
// For sending you create a new instance and giving the container to a portal
public class TestContainer : Container
{
   // be careful by using write protected 'const' container IDs for 'switch', do not use 'public'
   internal const ushort myContainerID = 1;

   // Only public, non-static and standard datatypes can be transmitted
   public string message = "default message";

   // Also 1D arrays are possible
   public int[] array = new int[1000];
}

Event handling functions:

When a Client connects to a Server, Vaser raises standard Events like 'on new connection', 'on disconnect' or when the buffer of the sending queue is empty.

// Use for every function a separate container
TestContainer con4 = new TestContainer();
static void OnNewLink(object p, LinkEventArgs e)
{
   Console.WriteLine("Client connected from IP: " + e.lnk.IPv4Address);

   // Delegate a function if the buffer of the link is empty
   // see at “Send a message” for more details
   e.lnk.EmptyBuffer += OnEmptyBuffer;

   //To do: add the link to your connected client list

   // you can attach a custom ID and an object the link
   // create your own client class and attach it to the link
   // Note: Vaser has no client class, this is an example
   Client myClient = new Client();
   myClient.lnk = e.lnk; // attach the link to the client class
   e.lnk.AttachedID = myID;
   e.lnk.AttachedObject = myClient;

   // new links needs to be accepted
   e.lnk.Accept();
}

// Use for every function a separate container
TestContainer con5 = new TestContainer();
static void OnDisconnectingLink(object p, LinkEventArgs e)
{
   Console.WriteLine("Client disconnected from IP: " + e.lnk.IPv4Address);
   
   // for exemple: you can get a custom attached object from your link
   Client myClient = (Client)e.lnk.AttachedObject;
}

// Use for every function a separate container
TestContainer con6 = new TestContainer();
static void OnEmptyBuffer(object p, LinkEventArgs e)
{
   // Warning: operate threadsafe here!
   Console.WriteLine("OnEmptyBuffer called!");
}

Initialize a portal collection:

The portals are attached to the data processing methods.

// Before a server or a client can be created, you need a portal collection and portals
// delegate your data processing function to the portal event handler
// Note: The Portal ID is the priority of the QoS management. Please set all file transfers on ID 255!
static Portal system = null;
static Portal login = null;
static Portal files = null;
static PortalCollection PColl = null;

static void CreatePortalCollection()
{
   system = new Portal(100); // Portal ID 100 - first priority
   system.IncomingPacket += OnSystemPacket;

   login = new Portal(101); // Portal ID 101 - second priority
   login.IncomingPacket += OnLoginPacket;

   files = new Portal(255); // Portal ID 255 - last priority
   files.IncomingPacket += OnFilesPacket;

   PColl = new PortalCollection(); // The portal collection
   // portals can be used with multiple collections
   PColl.RegisterPortal(system);
   PColl.RegisterPortal(login);
   PColl.RegisterPortal(files);
}

// Use for every function a separate container
TestContainer con1 = new TestContainer();
static void OnSystemPacket(object p, PacketEventArgs e)
{
   // ToDo

   // for exemple: you can get a custom attached object from your link
   Client myClient = (Client)e.lnk.AttachedObject;
}

// Use for every function a separate container
TestContainer con2 = new TestContainer();
static void OnLoginPacket(object p, PacketEventArgs e)
{
   // ToDo
}

// Use for every function a separate container
TestContainer con3 = new TestContainer();
static void OnFilesPacket(object p, PacketEventArgs e)
{
   // ToDo
}

Start the server:

// Start the server
// The Server is now listen on port 1000 on all adapters.
// The stream is secured and encrypted by Kerberos. More info at: https://msdn.microsoft.com/en-us/library/bb742516.aspx
// Typical used in Domain infrastructures.
//   Supported Modes:
//    - Not Encrypted
//    - Kerberos
//    - SSL TLS 1.2
// Portal Collection: the collection you have created
static VaserKerberosServer vkerberos = null;
static VaserServer Server = null;

static void StartServer()
{
   CreatePortalCollection();

   vkerberos = new VaserKerberosServer();
   Server = new VaserServer(System.Net.IPAddress.Any, 1000, PColl, vkerberos);

   // Delegate your action processing function to the server event handler
   Server.NewLink += OnNewLink;
   Server.DisconnectingLink += OnDisconnectingLink;

   // start the server
   Server.Start();

   Console.WriteLine("Server has started.");
   // you can now pause your console
   Console.ReadKey();
}

Connect a client:

// First, initialize the portals like on the server side
// Connect the client to the Server
//   Supported Modes:
//    - Not Encrypted
//    - Kerberos
//    - SSL TLS 1.2
// Portal Collection: the collection you have created

static Link ConnectClient(string ServerAddress, int Port)
{
   try
   {
      if(PColl == null) CreatePortalCollection();

      VaserKerberosClient ckerberos = new VaserKerberosClient();
      Link lnk = VaserClient.ConnectClient(ServerAddress, Port, PColl, ckerberos);

      // delegate your disconnecting function to the disconnecting event handler
      lnk.Disconnecting += OnDisconnectingLink;
      return lnk;
   }
   catch
   {
      MessageBox.Show("can't connect to " + ServerAddress + ":" + Port);
      return null;
   }
}

Send a message:

// Create a new container, should be reused
// Note: the container is not threadsafe
	TestContainer con = new TestContainer();
// Save the message in the container
	con.message = "transmitting a message via Vaser.";
// Send the message through the portal to the client
	system.SendContainer(link, con, 1, 1);
// Hint: the last two digits are the containerID and the objectID
// ->   system.SendContainer(link, con, containerID, objectID);
// These are the <Packet_Recv>.ContainerID and <Packet_Recv>.ObjectID on the receive side
// You can send as well empty packets for commands:
// system.SendContainer(link, null, 2, 1);

// if you want that a link rises the empty buffer event use this:
	system.SendContainer(link, null, TestContainer.myContainerID, 1, true);

Receive a message:

// a packet was send ->  system.SendContainer(link, con, containerID, objectID);

public void OnLoginPacket(object sender, PacketEventArgs e)
{
   try
   {
      // convert the attached object back
      Client c = (Client)e.lnk.AttachedObject;

      // assign your used container
      switch (e.pak.ContainerID)
      {
         case TestContainer.myContainerID: // packet ID 1
            // To do: packet logic here

            // try to decrypt the incoming packet
            TestContainer con = new TestContainer(); // Better to use an existing container
            if(con.UnpackContainer(e.pak)) // Is true if the decode of the packet was successful
            {
               Console.WriteLine(con.message);
            } // maybe on false disconnect the client?
            
            break;
      }
   }
   catch
   {
      // On any error, disconnect the client
      e.lnk.Dispose();
   }
}

Disconnect a client:

lnk.Dispose();

Stoping a Server:

// Stops the server
Server.Stop();

Reqeust/response pattern

Request receive class on the server side:

using System;
using Vaser;
using Vaser.OON;

namespace test_server
{
    public class TestRequest : cRequest
    {
        TestContainer con1 = new TestContainer();
        public override void IncomingRequest(object p, PacketEventArgs e)
        {
            if (con1.UnpackContainer(e.pak))
            {
                Console.WriteLine(con1.test);
                con1.test = "Hello Back!";

                RequestResponse(con1);
            }
            else
            {
                RequestResponse(null);
            }
        }
    }
}

Response send and receive class on the client side:

using System;
using Vaser;
using Vaser.OON;

namespace test_client
{
    public class TestRequest : cRequest
    {
        TestContainer con1 = new TestContainer();
        public cStatus myRequestStarter(string myMessage, Link lnk)
        {
            con1.test = myMessage;

            return StartRequest(lnk, con1);
        }

        TestContainer con2 = new TestContainer();
        public override void RequestResult(object p, PacketEventArgs e)
        {
            if (con2.UnpackContainer(e.pak))
            {
                Console.WriteLine(con2.test);

                SetDone("myResult");
            }
            else
            {
                SetError("Decode error.");
            }
        }

    }
}

Register the request at the PortalCollection, same goes for the channeling:

    Portal system = new Portal(100);
    PortalCollection PC = new PortalCollection();
    PC.RegisterPortal(system);
    system.IncomingPacket += OnSystemPacket;

    TestRequest myRequest = new TestRequest();
    PC.RegisterRequest(myRequest, system, 501);

    TestChannel myChannel = new TestChannel();
    PC.RegisterChannel(myChannel, system, 502);

    // ... start your server here...

    // usage:
    cStatus requestStatus = myRequest.myRequestStarter("Hello World!", clientLink);
    requestStatus.Wait();
    Console.WriteLine((string)requestStatus.ResultObject);

Channel pattern

Server side:

using System;
using Vaser;
using Vaser.OON;

namespace test_server
{
    public class TestChannel : cChannel
    {
        TestContainer con1 = new TestContainer();
        public void mySendStarter(string myMessage, Link lnk)
        {
            con1.test = myMessage;

            SendPacket(con1, lnk);
        }

        TestContainer con2 = new TestContainer();
        public override void IncomingPacket(object p, PacketEventArgs e)
        {
            if (con2.UnpackContainer(e.pak))
            {
                Console.WriteLine(con2.test);
                con2.test = "Hello Back channel!";

                SendPacket(con2);
            }
            else
            {
                Console.WriteLine("Decode error!");
            }
        }
    }
}

On the client side:

using System;
using Vaser;
using Vaser.OON;

namespace test_client
{
    public class TestChannel : cChannel
    {
        TestContainer con1 = new TestContainer();
        public void mySendStarter(string myMessage, Link lnk)
        {
            con1.test = myMessage;

            SendPacket(con1, lnk);
        }

        TestContainer con2 = new TestContainer();
        public override void IncomingPacket(object p, PacketEventArgs e)
        {
            if (con2.UnpackContainer(e.pak))
            {
                Console.WriteLine(con2.test);

            }
            else
            {
                Console.WriteLine("Decode error!");
            }
        }

    }
}