 |
Cliser Examples: A Random Quote Service using UDP over TLI |
 |
As an example of a non-standard service,
we will in this example write a server that provides
a randomly-selected quote from a file of quotes,
and a client to read and display a quote from the server.
Providing this service should not take very long,
and so we will use the UDP communications protocol,
single-threading, and C++.
For lack of a better number, our server will use port 9876.
Its constructor will read the quotations from a data file,
and store them in a vector of strings named quotes.
When it receives a message from a client, our server will simply
generate a random integer i in the range of valid vector
indices, and then send to the client the string in
quotes[i].
A UDP random quotes client thus sends a message to a random quotes server,
and then reads and displays the server's reply.
To build a client and server for the daytime service, we follow the
steps described previously:
1. Use Cliser
1a. Run Cliser.
The nicest interface for Cliser is a graphical user interface
written in Java.
To run it, enter:
$ java cliser.GUI
This will display the Cliser graphical user-interface, as shown
below:
1b. Enter Parameters.
We then enter the name of our service (RandomQuotes),
the port is should use (9876), and
the protocol we want to use (UDP);
indicate what we want to generate ( both a client and a server),
specify the language we want to generate (C++),
the network interface we want to use (choose one appropriate
for your OS/platform -- we'll use AT&T Unix TLI here),
and the kind of server we want (Iterative/single-threaded).
1c. Generate Source Code.
In the GUI interface, we then click the Generate button.
This generates the files
RandomQuotes_UDP_TLI_Client.cpp
and RandomQuotes_Iterative_UDP_TLI_Server.cpp.
We then click the Quit button to quit using Cliser.
2. Customize the Source Code
Since we are building both a client and a server,
we must customize both of the files generated in the previous step.
2a. Customize the Server
Using our favorite text editor, we
-
open the file
RandomQuotes_Iterative_UDP_TLI_Server.cpp
-
#include the necessary libraries
(e.g., <vector>) and
define a myQuotes attribute variable in class
RandomQuotes_UDP_TLI_Server:
private vector<string> myQuotes;
-
add code to the constructor to initialize myQuotes:
RandomQuotes_Iterative_UDP_TLI_Server::RandomQuotes_Iterative_UDP_TLI_Server(int port)
: Iterative_UDP_TLI_Server("RandomQuotes", port)
{
ifstream fin("quotes.txt");
string quote;
for (;;)
{
getline(fin, quote);
if ( fin.eof() ) break;
myQuotes.push_back(quote);
}
fin.close();
}
-
replace the comments in method
RandomQuotes_Iterative_UDP_TLI_Server::interactWithClient()
with statements that provide the required behavior:
void RandomQuotes_Iterative__UDP_TLI_Server::interactWithClient()
{
int randomIndex = rand() % myQuotes.length();
string discard;
this->receive(discard);
this->send(myQuotes[randomIndex]);
}
-
Using a text editor,
create a data file of quotes (quotes.txt) that the
constructor expects to find:
No matter where you go, there you are. -- Buckaroo Banzai
To be or not to be, that is the question. -- Shakespeare (Hamlet)
Mein Fuehrer, I can walk! -- Stanley Kubrick (Dr. Strangelove)
Our server customization is this simple because of the Cliser
system architecture
which, among other things, provides the easy-to-use,
protocol-independent send() and receive()
communication primitives.
Note that because the UDP protocol is connectionless,
our method must get (and discard) a message from the client
before it can know the client to which the random quote
must be sent.
The result is the file
RandomQuotes_Iterative_UDP_TLI_Server.cpp.
2b. Customize the Client
Again using our favorite text editor, we open the file
RandomQuotes_UDP_TLI_Client.cpp
and replace the comments in the body of method
RandomQuotes_UDP_TLI_Client::interactWithServer()
with statements that define the required behavior:
void RandomQuotes_UDP_TLI_Client::interactWithServer()
{
string quoteReceived;
this->send("Hi");
this->receive(quoteReceived);
cout << quoteReceived << endl;
}
The result is the file
RandomQuotes_UDP_TLI_Client.cpp.
As was the case with our server, our client customization is
straightforward thanks to Cliser's simple
send() and receive()
communication primitives.
3. Compiling and Linking
Once we have customized the files generated by Cliser,
we can compile each as we would any other C++ program file.
On a system using BSD or TLI, we might use the automatically generated
Makefile
When executed via make,
this file creates the binary executable files
RandomQuotesd for the server ('d' stands for 'daemon'), and
RandomQuotes for the client.
Because Cliser-generated clients and servers are derived from
classes in the
Cliser class library
you must have the cliser header and library files
installed in folders/directories on your system and inform your
compiler and linker of their locations. (The generated Makefile
uses the default installation directories).
4. Deploy and Run
To deploy your client, copy its binary executable file to a directory
that is listed in the PATH variable of your users
(e.g., /usr/local/bin).
If you wish for your users to be able to execute your server
(maybe not such a good idea, unless you want lots of redundant
servers running on your system), it can be deployed the same way.
4a. Running the Server
You can run the server (as the system administrator) as follows:
$ RandomQuotesd
The server can also be run using another port,
as shown in the other examples.
4b. Running the Client
If your server is using port 9876
on the machine myMachine.myDomain,
you can run the client to it with:
$ RandomQuotes myMachine.myDomain
If your server is using a different port,
that port can be specified via a command-line argument,
as shown in the other examples.
A sample client session might be as follows:
To be or not to be, that is the question. - Shakespeare (Hamlet)
This page maintained by
Joel Adams.