To Cliser Home

Cliser Examples: TCP/IP (TCP) Echo Service over Winsock

To Cliser
Architecture

Echo is a standard TCP/IP service used primarily for testing reachability, debugging software, and identifying routing problems. The service is defined for both the TCP and UDP communication protocols. In this example, we will build a client and server for the echo service in C++ using TCP.

An echo server listens for clients on port 7. When it receives a message from a client, an echo server simply transmits the message it received back to the client. A TCP (connection-oriented) echo server continuously echoes what the client sends it until the connection is closed.

A TCP daytime client thus connects to an echo server, reads what the user enters and sends it to the server, and then reads and displays the server's reply, until the user enters some kind of end-of-input sentinel (e.g., control-d, or the string quit).

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 (Echo), the port is should use (7), and the protocol we want to use (TCP); 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 WINSOCK sockets here), the kind of server we want (Concurrent/multithreaded), and the kind of concurrency we want (POSIX threads):

1c. Generate Source Code.

In the GUI interface, we then click the Generate button. This generates the files Echo_TCP_Winsock_Client.cpp and Echo_POSIX_Concurrent_TCP_Winsock_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 Echo_POSIX_Concurrent_TCP_Winsock_Server.cpp and replace the comments in method Echo_TCP_Winsock_Thread::interactWithClient() with statements that provide the required behavior:
  void Echo_TCP_Winsock_Thread::interactWithClient()
  {
    string message;
    int numCharsReceived;
    for (;;)
    {
       numCharsReceived = this->receive(message);
       if (numCharsReceived == 0 || message == "") break;
       this->send(message);
    }
  }
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 TCP protocol is connection-oriented, and the client connection is accepted prior to the execution of interactWithClient(), our method need only define what the server does to interact with the client.

The result is the file Echo_POSIX_Concurrent_TCP_Winsock_Server.cpp.

2b. Customize the Client

Again using our favorite text editor, we open the file Echo_TCP_Winsock_Client.cpp and replace the comments in the body of method Echo_TCP_Winsock_Client::interactWithServer() with statements that define the required behavior:
  void Echo_TCP_Winsock_Client::interactWithServer()
  {
    string messageSent, messageReceived;
    const string SENTINEL = "quit";
    cout << "Enter lines of text (" << SENTINEL << " to quit)\n";
    for (;;)
    {
      getline(cin, messageSent);
      if ((messageSent == SENTINEL) || cin.eof()) break;
      this->send(messageSent);
      this->receive(messageReceived);
      cout << messageReceived << endl;
    }
  }
The result is the file Echo_TCP_Winsock_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 need to compile and link the files. Here, we will show how to create a client and server Win32 console application using Microsoft's Visual C++.

If you haven't done so already, you should extract the Cliser library code. For example you could extract the files using WinZip to C:\CLISER\. You will want to copy the LIB files ( cliser.lib and pthread.lib, from the directory CLISER\LIB\C++\WINSOCK) into the Visual C++ Library directory, which may be C:\Program Files\Microsoft Visual Studio\VC98\LIB\.

Once the files are extracted, we can run Visual C++. We want to create a new blank workspace. From the File menu, select New. Select the Workspaces tab, enter in a Workspace name. "Echo" in our example. Your location can be anywhere (ie: C:\CLISER\ECHO).

In this new workspace, we need to add two Win32 Console Application projects. You may create these projects by selecting New from the File menu. Select the projects tab, and then the approriate entry. Ensure that "Add to current workspace" is selected for both of the projects. You should name your servers approriately. For the Echo programs, I called the applications "EchoClient" and "EchoServer". You may wish to modify the Cliser generated files to suit your own purposes after adding them to the project, so that you may use the IDE (Intergrated Development Environment).

The next step is to add the correct files to the projects. Choose the client first, by going to the Project menu, Set Active Project and the name of your client. Then, again, goto the Project menu, Add To Project, and Files. This will bring up a file dialog box. From here you should find your Cliser generated client source code, Echo_TCP_Winsock_Client.cpp in our case. Then we select the server project, and add to it the Cliser generated server source code, Echo_POSIX_Concurrent_TCP_Winsock_Server.cpp in our case.

The last step before compiling is to configure the projects. Bring up the Workspace window (View, Workspace), click on FileView, and select Workspace ..., at the top of the list. This allows us to configure both projects properly at the same time. Now we can goto the Settings in the Project menu. Change the "Settings For" option to "All Configurations". Select the C/C++ tab. Change Category to Preprocessor. Now add the Cliser include path to the "Additional include directories:" listing.

Next, change category to "C++ Language", and we enable Run-Time Type Information (RTTI). We also need to tell Visual C++ that we would like to link our program to a few non-standard libraries. We do this by clocking on the Link tab, beside the C/C++ tab. Under Category General, we add three libraries to the Object/library modules: ws2_32.lib cliser.lib pthread.lib.

Everything should now be configured properly. We may now test to make sure it works, by selecting Rebuild All from the Build menu. If you are happy with your program, you may compile the program for releaseing by going the the Build menu, Set Active Configuration, to the approriate Release configuration.

All of the Cliser code is statically linked. So, if you did not use the pthread library (ie. in the client), you should be able to distribute the compiled program as is. If you used the pthread library, you will also need to distribute the pthread.dll. Pthread.dll needs to be in the same directory as the executable, or in the DOS search PATH. For most people the C:\WINDOWS\ directory will work perfectly.

Note: When building with the Debug configuration, you may receive a linking warning like this: LINK : warning LNK4098: defaultlib "LIBC" conflicts with use of other libs: use /NODEFAULTLIB:library. This warning can safely be ignored. When building under Release configurations, this warning does not appear.

4. Deploy and Run

To deploy your client or server, copy the executable file to a new directory.

4a. Running the Server

You can run the server as follows:
  $ ServerExeName
If you are not the system administrator, you can still run the server by giving a different port as a command-line argument:
  $ ServerExeName 7777
This allows a server written for a standard service to be thoroughly tested before it is deployed. It also allows server-writers without sysadmin status to test their servers on unrestricted ports.

4b. Running the Client

You can run the client by specifying the host you want it to contact:
  $ ClientExeName ursa.calvin.edu
or if your server is listening at port 7777 on myMachine.myDomain:
  $ ClientExeName myMachine.myDomain 7777
A sample client session might be as follows:
  tasting, tasting     client
  tasting, tasting     server
  strawberry           client
  strawberry           server
  lemon                client
  lemon                server
  orange               client
  orange               server
  quit


Up to the Cliser home page Up to the Examples A UDP Client/Server for the standard Daytime Service using Java A TCP Client/Server for the standard Echo Service using C++ over BSD A UDP Client/Server for a Random Quotes Service using C++ over TLI A TCP Client/Server for a Knock-Knock Service using Java


This page maintained by Joel Adams.