2.2 Operation
To understand how the Essential Networking Module works, we can divide its classes informally into two categories: network concepts, and network streams.
Classes in the network concepts category encapsulate basic network abstractions. For example, class RWSocket encapsulates a traditional network socket; class RWInetAddr encapsulates a complete Internet address. Classes like these, implemented on top of the networking capabilities of your operating system, provide an object-oriented API for low-level network access, and give you complete control over individual socket attributes and behavior. Many of these classes and methods are similar to types and functions found in the APIs of operating system sockets.
Classes in the network streams category make it possible to use the C++ iostreams facility reliably over network connections. Classes such as RWPortal, RWSocketPortal, and RWPortalStreambuf allow you to stream data over the network using familiar iostreams classes. Combine network streams classes with the Essential Tools Module virtual streams and you can stream objects in compact form. Combine network streams classes with the XML Streams Module classes and you can stream XML representations. In short, the Essential Networking Module lets you treat the network as a stream.
2.2.1 A Simple Code Example
Here is a simple example that combines classes from the networking concepts and networking streams categories to send the traditional “Hello, World!” message over the Internet:
 
#include <rw/rstream.h>
#include <rw/network/RWSocketPortal.h>
#include <rw/network/RWInetAddr.h>
#include <rw/network/RWWinSockInfo.h>
#include <rw/network/RWPortalOStream.h>
 
int main()
{
RWWinSockInfo info; // 1
RWSocketPortal p(RWInetAddr(3010,"net.roguewave.com")); // 2
RWPortalOStream ostrm(p); // 3
ostrm << "Hello, World!" << endl; // 4
return 0;
}
On //1, the code initializes the Winsock DLL to make the example portable to Windows; this has no effect on UNIX. In //2 through //4, the code then constructs a socket portal as its access point to the communication stream, constructs an output stream using that socket portal as a parameter, and sends the message through the output stream over the network.
Overall, the example demonstrates how the Essential Networking Module encapsulates low-level programming details within an intuitive C++ interface. In a straightforward way, you can open and close connections, send and receive data, and perform virtually all aspects of network programming using the Essential Networking Module.
2.2.2 A Comparative Code Example
The advantage of using the Essential Networking Module can be demonstrated by comparing its code to code for the same operations using traditional C++. If you have experience in network programming in C++, you may have used code like this to look up a network host and all its aliases from a DNS server:
 
// Without the Essential Networking Module,
// using any standard C++ library
const char* s = "209.119.36.154"; // or "www.roguewave.com"
string hostname;
vector<std::string> aliases;
unsigned long address;
vector<unsigned long> addresses;
 
struct hostent* hp = 0;
// Is the string a dotted decimal address or host name?
unsigned long addr = inet_addr(s);
 
// Do DNS lookup for host information
if(addr != (unsigned long)-1)
hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET);
else
hp = gethostbyname(s);
 
// If DNS query was successful, continue
if(hp != 0)
{
// Get primary address
address = ((struct in_addr*) // 1
((hp->h_addr_list)[0]))->s_addr;
 
// Get host name
hostname = hp->h_name; // 2
// Get aliases
{ // 3
int n = 0;
if(hp->h_aliases)
for(char **ptr = hp->h_aliases; *ptr; ++ptr)
++n; // count aliases
 
aliases.resize(n);
 
for(int i = n; i--;)
aliases[i] = (hp->h_aliases)[i];
}
 
// Get addresses
{ // 4
int n = 0;
for(char **ptr = hp->h_addr_list; *ptr; ++ptr)
++n;
 
addresses.resize(n);
 
for(int i = n; i--; )
addresses[i] = ((struct in_addr*)
((hp->h_addr_list)[i]))->s_addr;
}
}
With the Essential Networking Module, you can write the same code as follows:
 
const char* s = "209.119.36.154"; // or "www.roguewave.com"
RWInetHost host(s);
unsigned long address = host.getAddress(); // 1
RWCString hostname = host.getName(); // 2
RWTValVector<RWCString> aliases = host.getAliases(); // 3
RWTValVector<unsigned long> addresses = host.getAddresses();
// 4
In both cases, the code accomplishes the same tasks: gets the primary address on //1; gets the host name on //2; gets the aliases on //3; and gets the other addresses on //4. However, the second example does the job with fewer steps, using a simpler, more intuitive interface, and less development time. Furthermore, it provides much more error-checking and type-safety than the first example.