-
Notifications
You must be signed in to change notification settings - Fork 1
Home
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.
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.
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.
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
.
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).
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).
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.
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).