Remote Communication Made Easy


This article was contributed by Ken Reed (see the demo project for contact details).

Environment: VC6, NT4, Windows 2000 Professional, XP Professional

Now that networked computers are so common, it is becoming an increasingly frequent programming task to get a program running on one PC to talk to one on another (as in multi-player games, for example). There are lots of ways to do it, but they all seem to require so much hard work. So, starting off with a blank sheet of paper, how would I like to send something to another program?

Well, if you want to send something to a file, you can just write the following (assuming the file is already open):

some_file << “Here is some value ” << some_value << “n”;

Seems easy enough. Why can’t you do exactly the same to send something to another program? Well, if you write a little bit of code you can, and you’ll find that code in the demo project in the file socket.cpp.

Behind the scenes it’s all done with sockets. However, I’m not going to teach you how to use sockets (there are some good books on that subject). The idea is for me to hide all the detail away so you don’t have to know how sockets work and you can just get on and get programs to talk to each other easily. Hopefully, the Socket class provided will let you do just that.

To use the socket class, you will need to include socket.h in your code and incorporate socket.cpp as a module. Having done that, you’re ready to go and you’ll find examples in the demo project. There is a little more to do than just streaming the things we want to send; we also have to do the equivalent of opening a file (for example, saying which computer and which program we want to talk to). Looking at the example demo project, we have two programs. One is a “server” that sits waiting for some other program to come and talk to it. When one does, it just writes the information coming from the other program into a window. The other program is the “client” that connects to the server and just sends it the time every second.

Ignoring all the Windows “plumbing” code, the server does the following:


string text;
Socket socket;
socket.bind(3333);
socket.listen();

while (true) {
socket >> text;

if (text == “exit”) {
socket << “okn”;

socket.close();
PostMessage(main_window, WM_CLOSE, 0, 0);
break;
}

SetWindowText(static_text, text.c_str());
}

The server first creates a socket. Then it tells it which port number to use (this is the bind call). A port number is needed so that more than one program on the same computer can all use sockets (as long as each program uses a different port number). The port number can be any number not in use on your computer (and should be greater than 1024). To find out which ports are in use, issue the following command from a DOS prompt:

netstat -a

The ports in use are the numbers after the colon in the local address column.

Next, the server calls the listen function. This basically waits until some other program wants to talk. When it does, the listen call returns and we can start reading data from the remote program. This is done just by using the >> operator. In this example, we’ve read in a string. If the string is “exit”, hen we close the socket and post a message to shut down the server (we also send back an “ok” to show that the communication isn’t just one-way). If it isn’t an exit command, we display the text in a window (the time in our demo example).

On the client side, the code is just as simple:


server.connect(“localhost”, 3333);

while (! shutdown) {
GetTimeFormat(0, 0, 0, 0, buffer, sizeof(buffer));
SetWindowText(static_text, buffer);

text = buffer;
server << text << “n”;

Sleep(1000);
}

string reponse;

server << “exitn”;
server >> response;

server.close();

The client issues a connect call saying which computer and which port (or program) it wants to connect to. In this case, we have used localhost to specify the local machine but it could be the computer name of anything on the network.

Having done that, it gets the time and sends it to the server. When shutting down, it sends an exit command to the server, asking it to shut down too (and reads back the response from the server although the demo program does nothing with it).

Note the end-of-line character (‘n’) when writing to the socket. This is important because the standard library likes streamed data to be surrounded by white space. Programs can appear to hang if you don’t provide it.

Try it out (the demo project was created using Visual Studio Version 6). Compile the client and server programs in the demo project and run the server. It will just display the text “Waiting”. Then, start the client. Both windows will then display the time, counting up in seconds. Now, close the client window. The server window will also close (because the client told it to shut down).

If all you want to do is get programs to talk to each other, you can stop reading now. However, if you want to “get technical,” read on.

Now, what are all those other things in the socket include file?

// This file needs -*- c++ -*- mode

I use emacs. If you do, too, you know what this means. If you don’t use emacs, you don’t care.

#include “exception.h”

C++ lets you handle errors with exceptions. Some people like them; some people don’t. I do, so if I detect an error, I throw an exception (the exception class that I use is included in the demo project). I recommend you use exceptions because they are a great help in debugging. Always put any code using the socket class inside a try block (note the caveat about streams below, though) and catch and report any errors. For example:


try {
my_routine_that_uses_sockets();
}
catch (Exception & e) {
MessageBox(0, e.get_error().c_str(), “Ooops!”,
MB_SETFOREGROUND);
}

Now, there is one thing to watch out for. If there is an error while you are streaming (using the << or >> operators), the standard library will catch the thrown exception and quietly set the stream state to bad or fail (depending on the error). If you stream your data, you must use the standard library error test functions fail() and bad() and not rely on an exception being caught.


void bind (const int port);
void close ();
void connect (const char * const host, const int port);
void listen ();

These have been covered in the example above; there’s really not much more to say apart from the fact that if you give a port number of zero to the bind call, it will automatically allocate a free port number. If you want to find out what number has been allocated, use the following call:

  int    get_number     ();

Of course, you still have to let the clients who want to talk to you know this number, but that is a little esoteric for this introductory article.


int bytes_read (bool reset_count = false);
int bytes_sent (bool reset_count = false);

You can read (and reset) the number of bytes sent and received over a socket. I used this when I wanted to display a progress bar while sending files over a socket.

  void   getline        (std::string & s);

The Microsoft string getline function doesn’t work with sockets (it can block forever). Consequently, this is a replacement (which also doesn’t include the eol character in the result … just a personal preference).


void read_binary (void * buffer, int buffer_size);
void write_binary (void * buffer, int buffer_size);

Streaming is great because it is just so easy to read (and modern PCs are so fast that it is rare that you notice the overhead). However, if you are sending lots of data very often (especially floating point numbers), it can be very CPU intensive (i.e. slow) converting everything to text and back. So, if you need performance, use these binary functions. Define a structure containing the elements you want to send and do a write_binary at the sender and a read_binary at the receiver. You won’t get data transfer between PCs much faster than that.

  void   set_trace      (const char * filename);

If things are not working as expected and you can’t figure out what’s going wrong, turn on tracing. Pass a file name to this function and everything streamed over the sockets will be logged to that file (another good reason for streaming). Look at it to see exactly what was sent and what was received by each program (saves bags of debug time).


void set_connection (void * handle);
void * get_connection ();

If you need to use these functions, you are smart enough to look at the code to find out what they do. The intended user of the Socket class does not need to go down to this level.


private:
Socket (const Socket & Socket); // No copying allowed

No copying of Sockets is allowed because I haven’t written a copy constructor … yet (and I’m not sure I want to). Why? The Socket class contains a buffer where it builds up a line of text to send. Taking a copy (passing the socket as a parameter to a function) and adding to the buffer (inside the function) and then reverting to the original buffer (returning from the function call) is just too error prone. I don’t even want to think about it. Does this mean you can’t pass a socket as a function parameter? No, it doesn’t; just pass it by reference rather than by copy. For example:

void my_function(Socket & socket);

Other Odds and Ends

“What versions of Windows will it run under?” I’ve tried it on NT4, Windows 2000 Professional, and Windows XP Professional. In principle, it should work on anything from Windows 95 onwards, but I haven’t been able to try it out on anything other than those three versions mentioned.

“What’s the deal on licencing?” The socket and exception class are free software. You can use, modify, and redistribute the code as described by the GNU Public Licence (version 2). A copy of the licence is included in the demo project.

“What’s in the demo project?” Ignoring the Visual Studio-generated files, you will find the following files in Socket_demo.zip:


Contact.txt How to contact me
Socket.html This article in CodeGuru HTML
format

commonexception.h Exception include file
commonexception.cpp Exception implementation
commonsocket.h Socket include file
commonsocket.cpp Socket implementation
commonGNU_Public_Licence.txt Software licence for the above
two classes

clientclient.cpp Demonstration client program

serverserver.cpp Demonstration server program

Downloads


Download demo project – 35 KB

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read