3. Your First AMPS Program¶
In this chapter, we will learn more about the structure and features of the AMPS C# library, and build our first C# program using AMPS.
About the Client Library¶
The AMPS client is packaged as a single managed assembly,
AMPS.Client.dll
You can find AMPS.Client.dll
in the AMPS/bin
directory of your AMPS C# client. Every .NET application you build will
need to reference this assembly file, and the assembly must be deployed
along with your application in order for your application to function
properly.
Connecting to AMPS¶
Let’s begin by writing a simple program that connects to an AMPS server and publishes a single message to a topic:
using System;
using AMPS.Client;
using AMPS.Client.Exceptions;
namespace AMPSBookExamples
{
class ConnectToAMPS
{
static void Main(string[] args)
{
using(Client client = new Client("exampleClient"))
{
try
{
client.connect("tcp://192.168.1.3:9007/amps");
client.logon();
client.publish("messages", @"{ ""message"" : ""Hello, World!"" }");
}
catch (AMPSException e)
{
Console.Error.WriteLine(e);
}
}
}
}
}
Example 3.1: Connecting to AMPS
In the preceding Example 3.1, we show the entire program; but future examples will isolate one or more specific portions of the code. The next section describes how to build and run the application and explains the code in further detail.
Build and Run¶
To build this program, create a new C# command-line project in Visual
Studio and add a reference to AMPS.Client.dll
using the “Add
Reference...”’ option in Visual Studio. Replace the code in
Program.cs
with the code in
Example 3.1,
and then modify the client.connect()
on line 14 with the address and
port of your AMPS server. Now, you should be able to compile and execute
the code, and if the AMPS server is running, the message Hello world
is published to the messages topic. If an error occurs, an exception
will be written to the console.
If the message is published successfully, there is no output to the console. We will demonstrate how to create a subscriber to receive messages in Chapter 4.
Examining the Code¶
Let us now revisit the code we listed earlier.
using System;
using AMPS.Client;
using AMPS.Client.Exceptions;
namespace AMPSBookExamples
{
class ConnectToAMPS
{
static void Main(string[] args)
{
// This line creates a new Client object. Client encapsulates a single connection
// to an AMPS server. Methods on Client allow for connecting, disconnecting,
// publishing, and subscribing to an AMPS server. The argument to the Client
// constructor, "exampleClient", is a name chosen by the client to identify itself
// to the server. Errors relating to this connection will be logged with reference
// to this name, and AMPS uses this name to help detect duplicate messages. AMPS
// enforces uniqueness for client names when a transaction log is configured, and
// it is good practice to always use unique client names. The using statement ensures
// that the connection underlying the client is disposed of before the program exists.
// Client implements the .NET IDisposable interface, making it easy to ensure that
// are freed when your Client is no longer in use. There is no need to
// disconnect the Client when it is protected by a using statement.
using(Client client = new Client("exampleClient"))
{
try
{
// At this point, we have a valid AMPS connection and can begin to use it to
// publish and subscribe to messages.
client.connect("tcp://192.168.1.3:9007/amps");
client.logon()
// Here, we publish a single message to AMPS on the messages topic, containing the
// data { "message" : "Hello, world!" }.
// This JSON message is sent to the server. Upon successful completion of this function,
// the AMPS client has sent the message to the server, and subscribers to the messages
// topic will receive this message.
client.publish("messages", @"{ ""message"" : ""Hello, World!"" }");
}
catch (AMPSException e)
{
Console.Error.WriteLine(e);
}
}
}
}
}
Client Names¶
AMPS uses the name of the client as a session identifier and as part of the identifier for a message. For this reason, when a transaction log is enabled in the AMPS instance (that is, when the instance is recording a sequence of publishes and attempting to eliminate duplicate publishes), an AMPS instance will only allow one application with a given client name to connect to the instance.
When a transaction log is present, AMPS requires the Client Name for a publisher to be:
- Unique within a set of replicated AMPS instances
- Consistent from invocation to invocation if the publisher will be publishing tthe same logical stream of messages
60East recommends always using consistent, unique client names. For example, the client name could be formed by combining the application name, an identifier for the host system, and the id of the user running the application. A strategy like this provides a name that will be different for different users or on different systems, but consistent for instances of the application that should be treated as equivalent to the AMPS system.
Connection Strings¶
The AMPS clients use connection strings to determine the server, port, transport, and protocol to use to connect to AMPS. When the connection point in AMPS accepts multiple message types, the connection string also specifies the precise message type to use for this connection. Connection strings have a number of elements.
Figure 3.1: elements of a connection string
As shown in the figure above, connection strings have the following elements:
Transport defines the network used to send and receive messages from AMPS. In this case, the transport is
tcp
. For connections to transports that use the Secure Sockets Layer (SSL), usetcps
.Host address defines the destination on the network where the AMPS instance receives messages. The format of the address is dependent on the transport. For
tcp
andtcps
, the address consists of a host name and port number. In this case, the host address islocalhost:9007
.Protocol sets the format in which AMPS receives commands from the client. Most code uses the default
amps
protocol, which sends header information in JSON format. AMPS supports the ability to develop custom protocols as extension modules, and AMPS also supports legacy protocols for backward compatibility.MessageType specifies the message type that this connection uses. This component of the connection string is required if the protocol accepts multiple message types and the transport is configured to accept multiple message types. If the protocol does not accept multiple message types, this component of the connection string is optional, and defaults to the message type specified in the transport.
Legacy protocols such as
fix
,nvfix
andxml
only accept a single message type, and therefore do not require or accept a message type in the connection string.
As an example, a connection string such as
tcp://localhost:9007/amps/json
would work for programs connecting from the local host to a
Transport
configured as follows:
<AMPSConfig>
...
<!-- This transport accepts any known message type for the instance: the
client must specify the message type. -->
<Transport>
<Name>any-tcp</Name>
<Type>tcp</Type>
<InetAddr>9007</InetAddr>
<Protocol>amps</Protocol>
</Transport>
...
</AMPSConfig>
See the AMPS Configuration Guide for more information on configuring transports.
Providing Credentials in a Connection String¶
When using the default authenticator, the AMPS clients support the standard format for including a username and password in a URI, as shown below:
tcp://user:password@host:port/protocol/message_type
When provided in this form, the default authenticator provides the username and password specified in the URI. If you have implemented another authenticator, that authenticator controls how passwords are provided to the AMPS server.
Connection Parameters¶
When specifying a URI for connection to an AMPS server, you may specify a number of transport-specific options in the parameters section of the URIconnection parameters. Here is an example:
tcp://localhost:9007/amps/json?tcp_nodelay=true&tcp_sndbuf=100000
In this example, we have specified the AMPS instance on localhost
,
port 9007
, connecting to a transport that uses the amps
protocol
and sending JSON messages. We have also set two parameters,
tcp_nodelay
tcp_nodelay, a Boolean (true/false) parameter, and
tcp_sndbuf
tcp_sndbuf, an integer parameter. Multiple parameters
may be combined to finely tune settings available on the transport.
Normally, you’ll want to stick with the defaults on your platform, but
there may be some cases where experimentation and fine-tuning will yield
higher or more efficient performance.
AMPS supports the value of tcp
in the connection string for TCP/IP
connections, and the value of tcps
in the connection string for SSL
encrypted connections.
Transport options¶
The following transport options are available for TCP connections:
bind |
(ip address) Sets the interface to bind the outgoing socket to. |
tcp_rcvbuf |
(integer) Sets the socket receive buffer size. This defaults to the
system default size. (On Linux, you can find the system default size
in /proc/sys/net/core/rmem_default .) |
tcp_sndbuf |
(integer) Sets the socket send buffer size. This defaults to the
system default size. (On Linux, you can find the system default size
in /proc/sys/net/core/wmem_default .) |
tcp_nodelay |
(boolean) Enables or disables the TCP_NODELAY setting on the
socket. By default TCP_NODELAY is disabled. |
tcp_linger |
(integer) Enables and sets the SO_LINGER value for
the socket. By default, SO_LINGER is enabled with a value of
10 , which specifies that the socket will linger for 10 seconds. |
tcp_keepalive |
(boolean) . Enables or disables the SO_KEEPALIVE
value for the socket. The default value for this option is true. |
AMPS additional logon options¶
The connection string can also be used to pass logon parameters to AMPS. AMPS supports the following additional logon option:
pretty |
Provide formatted representations of binary messages rather than the original message contents. |
Next Steps¶
Once your application is built, you will need to think about how to
deploy it to additional computers. With your application’s dependency on
AMPS.Client.dll
, you need to include AMPS.Client.dll
along with
your application. The most straightforward way to accomplish this is to
install AMPS.Client.dll
into the same folder as your .exe
file.
For example, if you distribute your executable in a zip file that users
are expected to unpack, simply include AMPS.Client.dll
assemblies
into that zip file. When your executable runs, Windows will attempt to
load AMPS.Client.dll
from the same directory as your executable, and
if it is not found, your executable will fail to run.
If your organization develops and deploys many AMPS applications and
would like more centralized control over the maintenance of these AMPS
client deployments, consider installing AMPS.Client.dll
into the
Global Assembly Cache (“GAC”). The GAC allows you
to share one copy of an assembly — like the AMPS client — across many
applications on a computer. This technique requires that the assembly
have a strong name, and that you use an installer that places
AMPS.Client.dll
into the GAC. Installing the assembly in the GAC is
not recommended unless many applications will share an AMPS client. For
more information on the GAC, visit the Microsoft Developer Network
documentation on the GAC at
http://msdn.microsoft.com/en-us/library/yf1d93sz.aspx
.
You are now able to develop and deploy an application in C# that publishes messages to AMPS. In the following chapters, you will learn how to subscribe to messages, use content filters, work with SOW caches, and fine-tune messages that you send.