Client and Server Templates
back to iNetwork
Note
This code walkthrough explains what is in the client / server templates (which you should have when you installed the toolkit). You can (and should) use the Client and Server Templates as a basic starting point to writing iNetwork client and servers. The templates include all the basic structures you will need to get going: you modify the code to actually do something useful (examples are provided in the tutorials). provides instructions for how to create a basic client/server project using these templates (see recipes below).
Contents
Introduction
When using the iNetwork Toolkit to create solutions or applications there is a basic or general way to set-up client and server code. In other words, the main start-up code is the same every time a new project is made. Below you will find a brief discussion of details regarding the logic of the code found in each of the client and server templates. We recommend that you create a basic client/server solution following the instructions in , and then go through that as you read the descriptions below. Note that there may be a few things that you may not understand as you read this, but these will become clearer as you do the tutorials.
back to top
Template Regions
As you go through each of the client and server templates, you will notice that the code has been organized into four chunks or regions.
- Class Instance Variables
- Constructor
- Initialization
- Main Body
All global instance variables will be found and declared within the Class Instance Variables region. This includes the connection for the client and the server for the server.
The Constructor region mainly holds the constructor for the UI's main window.
The contents of the Initialization region include the InitializeConnection method for the client and the InitializeServer and OnServerConnection methods for the server. These methods have a hand in discovering and establishing the connection between the client(s) and the server.
Finally the Main Body region contains the OnMessageReceived event handler method for the client and the OnConnectionMessage event handler method for the server. This region will contain any other methods, event handler methods, and general functionality for the program.
back to top
Client
Initialization
Within the Class Instance Variables region, a Connection class instance variable is declared. This variable will represent the connection that is made between the client and the server.
- private Connection _connection;
The InitializeConnection method, found in the Initialization region, is called in the MainWindow Constructor. It is in this method that the client attempts to discover a connection.
- Connection.Discover("Name-of-Service", new SingleConnectionDiscoveryEventHandler(OnConnectionDiscovered));
- Name-of-Service is the name of the service or connection that the client looks for.
In the event that the client does find a service, the SingleConnectionDiscorveryEventHandler calls on the OnConnectionDiscorvered event handler method. Within this method, the connection found is assigned to be the client's connection.
- this._connection = connection;
Now it checks whether or not the connection is null. In the case that it is not null, a ConnectionMessageEventHandler is created to handle the event in which messages are received via the connection. This is taken care of by the OnMessageReceived event handler method. Then the connection is started, where in the networking thread is initialized.
- if (this._connection != null)
- {
- this._connection.Start();
- }
If the connection is null the UI window is closed through the GUI thread.
- else
- {
- this.Dispatcher.Invoke(
- new Action(
- delegate()
- {
- this.Close();
- }
- ));
- }
Receiving Messages
As previously mentioned, the OnMessageReceived event handler method in the Main Body region is the method that is called when the client receives a message. In this method, the client first checks that the message is not null then it executes the appropriate actions depending on the message name. Any number of messages can be received depending on what the project or application is intended to do. The tutorials will show you how to modify this section to handle the message types you will want to create and use. Note that in the template, there is an available stub example.
- if (msg != null)
- {
- switch (msg.Name)
- {
- default:
- break;
- case "Name-of-Message":
- // Do something here
- break;
- }
- }
The above program currently does nothing, as it does not yet include any code that sends messages.
Sending Messages
A client is able to send one or more messages to the server and each message may contain different fields. Message sending is something you will do when you extend the client (the client template does not include this code). Creating a message is very simple.
Fields can be added to the message in order to send object values such as strings, integers and doubles to the server.
- msg.AddField("Value-Object");
Now it is time to send the message to the server. Note that if the client wants or needs to communicate with the server, it is able to send messages at any point while it is connected. Also, as previously mentioned, depending on the the task(s) assigned to the project or application there can be as little as one message type or as many as needed. You will, of course, have to modify the code in the OnMessageReceived event handler to handle that particular message.
- this._connection.SendMessage(msg);
back to top
Server
Initialization
A Server variable needs to be declared inside the Class Instance Variable region along with a list of connections to keep track of connected clients.
- private Server _server;
- private List<Connection> _clients;
The InitializeServer method, from the Initialization region, is called in the MainWindow Constructor. Here the client connection list is instantiated.
When the server is created, it becomes discoverable: clients trying to make a connection with the server can then find it.
- this._server.IsDiscoverable = true;
- "Name-of-Service", is the name of the server. This is what the client uses in order to find the server
- 12345 is the port number. This number can be any number between 1024 - 65535, inclusively. The port is where the server will be bound.
Next, a ConnectionEventHandler is created, thus any connection events will be managed by the OnServerConnection event handler method.
Finally the server is started on a networking thread, and the UI is updated to show the IP address and port number being used.
- this._server.Start();
- this._statusLabel.Content = "IP: " + this._server.Configuration.IPAddress.ToString()
- + ", Port: " + this._server.Configuration.Port.ToString();
The OnServerConnection event handler method includes two types of ConnectionEvents to check for: Connect and Disconnect.
If the connection event is a Connect event type, then the list of connections this._clients is locked. The keyword lock essentially acts as a lock and key. The thread, which in this case is the networking thread, "grabs" the lock. While that particular thread has "possession" of the lock no other thread can gain access to the "key". In other words, by locking the list the networking thread is the only thread allowed to manipulate or change the list until the lock is released.
- if (e.ConnectionEvent == ConnectionEvents.Connect)
- {
- lock (this._clients)
If the list does not already contain the given connection then it will be added to the list. A ConnectionMessageEventHandler is created to handle any message-received events. Any tasks that need to be executed are carried out by the OnConnectionMessage event handler method.
- if (this._clients.Contains(e.Connection))
- {
- this._clients.Remove(e.Connection);
Through the GUI thread the server's UI is updated to show the connection.
- this.Dispatcher.Invoke(
- new Action(
- delegate()
- {
- this._clientsList.Items.Add(e.Connection);
- }
- ));
Similarly, if the connection event type is Disconnect then the list of connections is locked so that only the networking thread is able to manipulate it. If the connection is already a part of the list of connections in this._clients, then the connection is removed from the list. As part of the "cleanup" process, the ConnectionMessageEventHandler is also removed for that connection.
- else if (e.ConnectionEvent == ConnectionEvents.Disconnect)
- {
- lock (this._clients)
- {
- if (this._clients.Contains(e.Connection))
- {
- this._clients.Remove(e.Connection);
Again the server's UI is updated through the GUI thread in order to remove the connection that has been disconnected.
- this.Dispatcher.Invoke(
- new Action(
- delegate()
- {
- this._clientsList.Items.Remove(e.Connection);
- }
- ));
Last but not least, a CancelEventHandler is created and handled by the OnWindowClosing event handler method. This method checks that the server is in fact not null and that it is running. When it confirms that this is true it stops the server (networking thread) when the UI window is closed.
- if (this._server != null && this._server.IsRunning)
- {
- this._server.Stop();
- }
- }
Receiving Messages
The server, just as the client, is able to send and receive messages. Through the OnConnectionMessage event handler method within the Main Body region the server receives and responds to messages.
- if (msg != null)
- {
- switch (msg.Name)
- {
- default:
- break;
- case "Name-of-Message":
- break;
- }
- }
Sending Messages
Sending messages from the server to the client is fairly simple and easy. Begin by creating a new message while also adding details, such as strings and integers, if need be, to the message.
- msg.AddField("Object-Value");
Actually sending the message is a little different from server to client. Instead of using the SendMessage method for the connection, the message will be broadcasted to the clients using the server.
- this._server.BroadcastMessage(msg);
Note that the BroadcastMessage method can take up to two parameters or arguments. The first argument will always be the message that needs to be sent out. The second argument, which is optional, normally contains the client connection, or list of client connections. This argument allows for the server to make exception when sending out messages. Any connection that has been specified in this argument will not receive the message.
- this._server.BroadcastMessage(msg, (Connection)"Connection-Sender");