Skip to content
Trevor Prinn edited this page Apr 8, 2017 · 11 revisions

SockLib

Socklib is a .net 4.5 dll that manages data and file transfer transactions between a client and a server. The library is used at both the server and client side. There are also Xamarin/Android and Xamarin/iOS builds that allow devices to act as either the client or server.

In Transaction mode, each transaction consists of a request message sent by the client, and a reply message sent back from the server. This operation is similar to that of an Ajax transaction between a Web client and server.

The library can also be used to set up non-transactional client/server communication (Listening mode), where messages can be sent between the two asynchronously, i.e. either end can send messages to the other at any time. The Server can also broadcast messages to all clients in Listening mode.

Messages

Several different types of message can be sent - each can be used by the client and the server.

Type Use
Text Sending some UTF-8 text.
Status Can be used as a text reply from the server to indicate a status and a text description of it.
Unicode Sending some Unicode text.
Xml Sending an XML document.
Binary Sending binary data.
Filenames Sending a list of filenames to be retrieved (automatically by the server).
Multipart Sending multiple sets of text, binary and/or file contents.

Custom Message Types (e.g. for Zipped or JSON data) can also be defined.

All messages contain header data with these fields:

Field Type Meaning
Type MessageTypes enum The type of message.
Command string Optional command to identify the action the other end should take.
Id string Optional unique identifier for the client across transactions.

The values used for the Command field are application specific, and mean nothing to the base client and server classes.

Each message type has two classes associated with it, one for sending a message, derived from SendMessage, and the other for receiving it, derived from RecMessage.

The header data in the table above for received messages is stored in a separate RecMessageHeader object within the RecMessage object, and also exposed as properties of the RecMessage object.

The other data in a SendMessage or RecMessage object depends on the class, which depends on the message type.

If the Id is not specified by the client, the server will supply a unique id in the reply. The Id field provides a similar facility to a Web cookie used to identify a session. For most apps, it will probably not be used.

Client Modes

A client can be set to operate in one of two modes, Transaction or Listening.

In Transaction mode messages are sent from the client to the server, and a reply received from the server synchronously, so that the Transaction call does not return until a reply is received.

In Listening mode, the server and client can send each other messages at any time, without expectation of a reply.

Client side in Transaction mode

Transactions are always initiated by the client app. A transaction consists of one message being sent by the client, and a reply being received from the server. A Client object is used to manage the transaction.

An example of the client code for a simple transaction:

using (Client c = new Client(hostname, port)) {
	var msg = new SendTextMessage("Hello", "This is me");
	var reply = c.Transaction(msg);
	if (reply is RecStatusMessage) {
		var status = (RecStatusMessage)reply;
		MessageBox.Show("Error: " + status.StatusMessage);
		return;
	}
	MessageBox.Show(((RecTextMessage)reply).Text);
}

This sends a text message with the command "Hello" and the text "This is me" to the server. It expects a text message back from the server, and displays it. If there is an untrapped error, the server may send back a RecStatusMessage.

Server side for a Transaction client

The server is started by creating a Server object. This listens on the specified port and handles messages as they are received, sending back replies. If the clients are set to Transaction mode a reply should always be sent, even it it is only signalling an error, otherwise the client may hang waiting for one.

Although in the example the client sends a SendTextMessage the server receives it as a RecTextMessage. Similarly the SendTextMessage the server sends as a reply is received as a RecTextMessage by the client.

A example of a simple handler for the client above:

var server = new Server(port);
server.MessageReceived += (object s, Server.MessageReceivedEventArgs e) => {
	if (e.Message.Header.Command != "Hello") return new StatusMessage("ERR", "Invalid command", "Expected Hello");
	var r = new SendTextMessage("Ack");
	var m = (RecTextMessage)e.Message;
	r.Text = m.Text == "This is me" ? "I knew that" : "Who are you?";
	e.Reply = r;
};

If the message command is not "Hello" a status message is returned.

(Generally it is easier to set up Handlers to manage the receipt of messages, rather than writing a handler for the MessageReceived event).

Client side in Listening mode

A client set to run in Listening mode cannot send Transactions. Instead, it sends messages to the server at any point, using its SendMessage method, and can receive messages at any time, in which case a MessageReceived event is raised (unless a Handler has been defined for the message). The messages sent and received are not coupled, so a client could send ten times as many messages as it receives, or vice versa.

A server handles the messages from a client in Listening mode in the same way as in Transaction mode, but does not have to set a Reply (if it does, it will be sent to the client).

Pings

In Listening mode the client and server will, by default, automatically ping each other periodically to ensure that the other end of the connection is still open and reachable. This is managed within the library and doesn't require any message handling by the application. This facility has been included to ensure that a client and server can respond quickly if the connection is lost, rather than waiting a much longer period for a network timeout to occur, for example. It also allows them to respond if, for example, a network cable becomes disconnected; something which could otherwise not easily be determined.

When a ping timeout occurs (i.e. the other end of the connection does not reply in time) the connection is dropped, and a ConnectionLost event is raised by the Client. At the Server end, the Server Client is closed and removed, as though it had disconnected.

The Ping parameters are set at the client end, and must be set before putting the client into Listening mode (normally after creating it but before opening it). The ping parameters are:

Property Type Meaning Default
SendPings bool Whether to send pings to the server (and whether the server should send its own pings) true
PingInterval int How often to send pings (in millisecs) 500
PingTimeout int The timeout period to wait for a reply 2000

When using Pings it is vital to ensure, at both ends, that the thread receiving the messages does not get blocked for too long while processing a message. See the Asynchronous Handlers section of the Handlers page for more information on how to deal with this.

Deriving classes

Classes can be derived from Client and Server to handle events or add application specific functionality. The same is true of the messages sent, which are themselves derived from SendMessage. Custom message types can also be defined by overriding SendMessage and ReceiveMessage to define a new message type, and registering the new ReceiveMessage class.

At the Server side a ServerClient object is created to manage each client currently connected to the server. This can be overridden by creating an instance of a derived class when the client first connects. A server could use this to store state information for and about the client (similar to a session object within a webserver).