579 lines
17 KiB
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> </td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td> </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> </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 <string>
|
|
|
|
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 <iostream>
|
|
#include <string>
|
|
|
|
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 <string>
|
|
|
|
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 <string>
|
|
|
|
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 <iostream>
|
|
#include <string>
|
|
|
|
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 © 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 ============================================================-->
|