old-www/LDP/LG/issue74/tougher.html

579 lines
17 KiB
HTML

<!--startcut ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>Linux Socket Programming In C++ LG #74</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->
<CENTER>
<A HREF="http://www.linuxgazette.com/">
<IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.png"
WIDTH="600" HEIGHT="124" border="0"></A>
<BR>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="spiel.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue74/tougher.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="zhaoway.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
<P>
</CENTER>
<!--endcut ============================================================-->
<H4 ALIGN="center">
"Linux Gazette...<I>making Linux just a little more fun!</I>"
</H4>
<P> <HR> <P>
<!--===================================================================-->
<center>
<H1><font color="maroon">Linux Socket Programming In C++</font></H1>
<H4>By <a href="mailto:rtougher@yahoo.com">Rob Tougher</a></H4>
</center>
<P> <HR> <P>
<!-- END header -->
<h2>Contents</h2>
<dl>
<dt><a href=#1>1. Introduction</a>
<dt><a href=#2>2. Overview of Client-Server Communications</a>
<dt><a href=#3>3. Implementing a Simple Server and Client</a>
<dd><a href=#3.1>3.1 Server - establishing a listening socket</a>
<dd><a href=#3.2>3.2 Client - connecting to the server</a>
<dd><a href=#3.3>3.3 Server - Accepting the client's connection attempt</a>
<dd><a href=#3.4>3.4 Client and Server - sending and receiving data</a>
<dt><a href=#4>4 Compiling and Testing Our Client and Server</a>
<dd><a href=#4.1>4.1 File list</a>
<dd><a href=#4.2>4.2 Compile and test</a>
<dt><a href=#5>5. Conclusion</a>
</dl>
<h2>1. Introduction</h2>
<a name=1></a>
<p>
Sockets are a mechanism for exchanging data between processes.
These processes can either be on the same machine, or on different machines
connected via a network. Once a socket connection is established, data
can be sent in both directions until one of the endpoints closes the
connection.
</p>
<p>
I needed to use sockets for a project I was working on, so I developed and refined
a few C++ classes to encapsulate the raw socket API calls. Generally, the
application requesting the data is called the client, and the application
servicing the request is called the server.
I created two primary classes, <b>ClientSocket</b> and <b>ServerSocket</b>, that the client
and server could use to exchange data.
</p>
<p>
The goal of this article is to teach you how to use the <b>ClientSocket</b> and <b>ServerSocket</b>
classes in your own applications. We will first briefly discuss client-server communications,
and then we will develop a simple example server and client that utilize these two classes.
</p>
<h2>2. Overview of Client-Server Communications</h2>
<a name=2></a>
<p>
Before we go jumping into code, we should briefly go over the set of steps
in a typical client-server connection. The following table outlines these steps:
</p>
<table width="400" cols=2 border=1>
<tr>
<td><b>Server</b></td>
<td><b>Client</b></td>
</tr>
<tr>
<td>1. Establish a listening socket and wait for connections from clients.</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>2. Create a client socket and attempt to connect to server.</td>
</tr>
<tr>
<td>3. Accept the client's connection attempt.</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>4. Send and receive data.</td>
<td>4. Send and receive data.</td>
</tr>
<tr>
<td>5. Close the connection.</td>
<td>5. Close the connection.</td>
</tr>
</table>
<p>
That's basically it. First, the server creates a listening socket, and
waits for connection attempts from clients. The client creates a socket
on its side, and attempts to connect with the server. The server then
accepts the connection, and data exchange can begin. Once all data
has been passed through the socket connection, either endpoint can close
the connection.
</p>
<h2>3. Implementing a Simple Server and Client</h2>
<a name=3></a>
<p>
Now its time to dig into the code. In the following section we will create both a
client and a server that perform all of the steps outlined above in the overview.
We will implement these operations in the order they typically happen - i.e. first
we'll create the server portion that listens to the socket, next we'll create the
client portion that connects to the server, and so on. All of the code in this
section can be found in <a href="misc/tougher/simple_server_main.cpp.txt">
simple_server_main.cpp</a> and
<a href="misc/tougher/simple_client_main.cpp.txt">simple_client_main.cpp</a>.
</p>
If you would rather just examine and experiment with the source code yourself, jump to
<a href=#4>this section</a>. It lists the files in the project,
and discusses how to compile and test them.
<h3>3.1 Server - establishing a listening socket</h3>
<a name=3.1></a>
<p>
The first thing we need to do is create a simple server that listens
for incoming requests from clients. Here is the code required to
establish a server socket:
</p>
listing 1 : creating a server socket ( part of <a href="misc/tougher/simple_server_main.cpp.txt">
simple_server_main.cpp</a> )
<div class=listing>
<pre>
#include "ServerSocket.h"
#include "SocketException.h"
#include &lt;string&gt;
int main ( int argc, int argv[] )
{
try
{
<b>// Create the server socket
ServerSocket server ( 30000 );</b>
// rest of code -
// accept connection, handle request, etc...
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
}
return 0;
}
</pre>
</div>
<p>
That's all there is to it. The constructor for the <b>ServerSocket</b> class
calls the necessary socket APIs to set up the listener socket. It hides the details
from you, so all you have to do is create an instance of this class to begin listening
on a local port.
</p>
<p>
Notice the try/catch block. The <b>ServerSocket</b> and <b>ClientSocket</b>
classes use the exception-handling feature of C++.
If a class method fails for any reason, it throws an exception
of type <b>SocketException</b>, which is defined in
<a href="misc/tougher/SocketException.h.txt">SocketException.h</a>.
Not handling this exception results in program
termination, so it is best to handle it. You can get the text of the error by calling
<b>SocketException</b>'s <b>description()</b> method as shown above.
</p>
<h3>3.2 Client - connecting to the server</h3>
<a name=3.2></a>
<p>
The second step in a typical client-server connection is the client's
responsibility - to attempt to connect to the server. This code is similar to the server
code you just saw:
</p>
listing 2 : creating a client socket ( part of <a href="misc/tougher/simple_client_main.cpp.txt">
simple_client_main.cpp</a> )
<div class=listing>
<pre>
#include "ClientSocket.h"
#include "SocketException.h"
#include &lt;iostream&gt;
#include &lt;string&gt;
int main ( int argc, int argv[] )
{
try
{
<b>// Create the client socket
ClientSocket client_socket ( "localhost", 30000 );</b>
// rest of code -
// send request, retrieve reply, etc...
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\n";
}
return 0;
}
</pre>
</div>
<p>
By simply creating an instance of the <b>ClientSocket</b> class, you create
a linux socket, and connect it to the host and port you pass to the constructor.
Like the <b>ServerSocket</b> class, if the constructor fails for any reason, an exception is thrown.
</p>
<h3>3.3 Server - accepting the client's connection attempt</h3>
<a name=3.3></a>
<p>
The next step of the client-server connection occurs within the server. It is the
responsibility of the server to accept the client's connection attempt, which opens
up a channel of communication between the two socket endpoints.
</p>
<p>
We have to add this functionality to our simple server. Here is the updated version:
</p>
listing 3 : accepting a client connection ( part of <a href="misc/tougher/simple_server_main.cpp.txt">
simple_server_main.cpp</a> )
<div class=listing>
<pre>
#include "ServerSocket.h"
#include "SocketException.h"
#include &lt;string&gt;
int main ( int argc, int argv[] )
{
try
{
// Create the socket
ServerSocket server ( 30000 );
<b>while ( true )
{
ServerSocket new_sock;
server.accept ( new_sock );</b>
// rest of code -
// read request, send reply, etc...
<b>}</b>
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
}
return 0;
}
</pre>
</div>
<p>
Accepting a connection just requires a call to the <b>accept</b> method. This method
accepts the connection attempt, and fills <b>new_sock</b> with the socket information about
the connection. We'll see how <b>new_sock</b> is used in the next section.
</p>
<h3>3.4 Client and Server - sending and receiving data</h3>
<a name=3.4></a>
<p>
Now that the server has accepted the client's connection request, it is
time to send data back and forth over the socket connection.
</p>
<p>
An advanced feature of C++ is the ability to overload operators - or simply, to make
an operator perform a certain operation. In the <b>ClientSocket</b> and <b>ServerSocket</b>
classes I overloaded the << and >> operators, so that when used, they wrote data
to and read data from the socket. Here is the updated version of the simple server:
</p>
listing 4 : a simple implementation of a server ( <a href="misc/tougher/simple_server_main.cpp.txt">
simple_server_main.cpp</a> )
<div class=listing>
<pre>
#include "ServerSocket.h"
#include "SocketException.h"
#include &lt;string&gt;
int main ( int argc, int argv[] )
{
try
{
// Create the socket
ServerSocket server ( 30000 );
while ( true )
{
ServerSocket new_sock;
server.accept ( new_sock );
<b>
try
{
while ( true )
{
std::string data;
new_sock >> data;
new_sock << data;
}
}
catch ( SocketException& ) {}
</b>
}
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
}
return 0;
}
</pre>
</div>
<p>
The <b>new_sock</b> variable contains all of our socket information, so we use it to
exchange data with the client. The line "new_sock >> data;" should be read as "read data
from new_sock, and place that data in our string variable 'data'." Similarly, the next line
sends the data in 'data' back through the socket to the client.
</p>
<p>
If you're paying attention, you'll notice that what we've created here is an echo server.
Every piece of data that gets sent from the client to the server gets sent back
to the client as is. We can write the client so that it sends a piece of data,
and then prints out the server's response:
</p>
listing 5 : a simple implementation of a client ( <a href="misc/tougher/simple_client_main.cpp.txt">
simple_client_main.cpp</a> )
<div class=listing>
<pre>
#include "ClientSocket.h"
#include "SocketException.h"
#include &lt;iostream&gt;
#include &lt;string&gt;
int main ( int argc, int argv[] )
{
try
{
ClientSocket client_socket ( "localhost", 30000 );
<b>
std::string reply;
try
{
client_socket << "Test message.";
client_socket >> reply;
}
catch ( SocketException& ) {}
std::cout << "We received this response from the server:\n\"" << reply << "\"\n";;
</b>
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\n";
}
return 0;
}
</pre>
</div>
<p>
We send the string "Test Message." to the server, read the response from the server,
and print out the response to std output.
</p>
<h2>4. Compiling and Testing Our Client And Server</h2>
<a name=4></a>
<p>
Now that we've gone over the basic usage of the <b>ClientSocket</b> and <b>ServerSocket</b>
classes, we can build the whole project and test it.
</p>
<h3>4.1 File list</h3>
<a name=4.1></a>
<p>
The following files make up our example:
</p>
<dl>
<dt>Miscellaneous:
<dd><a href="misc/tougher/Makefile.txt">Makefile</a> - the Makefile for this project
<dd><a href="misc/tougher/Socket.h.txt">Socket.h</a>,
<a href="misc/tougher/Socket.cpp.txt">Socket.cpp</a> - the
Socket class, which implements the raw socket API calls.
<dd><a href="misc/tougher/SocketException.h.txt">SocketException.h</a> - the SocketException class
<dt>Server:
<dd><a href="misc/tougher/simple_server_main.cpp.txt">simple_server_main.cpp</a> - main file
<dd><a href="misc/tougher/ServerSocket.h.txt">ServerSocket.h</a>,
<a href="misc/tougher/ServerSocket.cpp.txt">ServerSocket.cpp</a>
- the ServerSocket class
<dt>Client:
<dd><a href="misc/tougher/simple_client_main.cpp.txt">simple_client_main.cpp</a> - main file
<dd><a href="misc/tougher/ClientSocket.h.txt">ClientSocket.h</a>,
<a href="misc/tougher/ClientSocket.cpp.txt">ClientSocket.cpp</a>
- the ClientSocket class
</dl>
<h3>4.2 Compile and Test</h3>
<a name=4.2></a>
<p>
Compiling is simple. First save all of the project files into one subdirectory, then
type the following at your command prompt:
</p>
<div class=listing>
<pre>
prompt$ cd <i>directory_you_just_created</i>
prompt$ make
</pre>
</div>
<p>
This will compile all of the files in the project, and create the simple_server and
simple_client output files. To test these two output files, run the server in one
command prompt, and then run the client in another command prompt:
</p>
<div class=listing>
<pre>
<i>first prompt:</i>
prompt$ <b>./simple_server
running....</b>
<i>second prompt:</i>
prompt$ <b>./simple_client
We received this response from the server:
"Test message."</b>
prompt$
</pre>
</div>
<p>
The client will send data to the server, read the response, and print out
the response to std output as shown above. You can run the client
as many times as you want - the server will respond to each request.
</p>
<h2>5. Conclusion</h2>
<a name=5></a>
<p>
Sockets are a simple and efficient way to send data between processes. In this
article we've gone over socket communications, and developed an example
server and client. You should now be able to add socket communications to
your applications!
</p>
<!-- *** BEGIN bio *** -->
<SPACER TYPE="vertical" SIZE="30">
<P>
<H4><IMG ALIGN=BOTTOM ALT="" SRC="../gx/note.gif">Rob Tougher</H4>
<EM>Rob is a C++ software engineer in the NYC area.
When not coding on his favorite platform, you can
find Rob strolling on the beach with his girlfriend, Nicole,
and their dog, Halley.</EM>
<!-- *** END bio *** -->
<!-- *** BEGIN copyright *** -->
<P> <hr> <!-- P -->
<H5 ALIGN=center>
Copyright &copy; 2002, Rob Tougher.<BR>
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
Published in Issue 74 of <i>Linux Gazette</i>, January 2002</H5>
<!-- *** END copyright *** -->
<!--startcut ==========================================================-->
<HR><P>
<CENTER>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="spiel.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue74/tougher.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="zhaoway.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->