Network Communication Class Library

Iostreams and sockets in C++

Arjen Baart <arjen@andromeda.nl>

Mar 09, 2012

Document Information
Version0.2
OrganizationAndromeda Technology & Automation

Abstract:

The network communication class library encapsulates the UNIX socket layer for network communication and provides standard io stream functionality.

Table Of Contents

1 Problem Statement

1.1 TODO:

2 CLASSES

3 SCENARIOS

3.1 Make a stream socket connected to a specific host and service

3.2 Setup a listening stream socket

4 MEMBERS and METHODS

4.1 basic_sockstream

4.2 basic_isockstream

4.3 basic_osockstream

4.4 basic_sockbuf

4.5 Socket

4.6 StreamSocket

4.7 DatagramSocket

4.8 SocketAddress

4.9 UNIXSocketAddress

4.10 IPv4SocketAddress

4.11 IPv6SocketAddress

4.12 Service

4.13 Port

4.14 Host

4.15 InternetAddress


1 Problem Statement

The way processes communicate on the internet is through the use of -sockets-. The socket layer provides the interface between user processes and the network protocol stacks in the kernel of an operating system. A process can use a large variation of sockets, depending on the type of communication such as streams or datagrams or depending on the address familiy that is used like IPv6 or UNIX.

When two processes communicate through sockets, there is a socket on either side of the communication link. In other words, each process has its own socket while the underlying network stacks transfer the data from one socket to the other and vice versa. Which sockets take part in the communication is determined by the -host- and the -service- on which the socket resides. In many cases, the -service- also dictates the way the information is exchanged between the processes that hold the sockets.

In C++ standard iostream classes and objects exist to perform input and output operations on the controlling terminal of a process ('cin' and 'cout'), on files and device streams and on blocks of memory holding character strings. The socket stream classes provide this functionality for sockets in a way that is intended to be easy to use for the application programmer. Classes similar to the fstream and stringstream classes implement reading and writing data to and from sockets. At the highest level, an application is able to read data directly by specifying a URL, for example:

   string page;
   link = isockstream("http://www.andromeda.nl/index.html");
   link >> page;
At a slightly lower level, an application program would open a stream which connects to a host or address and a specific service. On the other hand, a server application would create a listening socket on a socket address and a service. Such a socket waits for incoming connection requests and after accepting a connection, a new socket is created through which the actual communication takes place. The new socket can then be used in creating an iostream object. Note that there can never be data transfer through a listening socket.

A socket needs an address to listen on or to connect to. Depending on the address family used, a socket address has a different set of attributes, such as a pathname for UNIX local addresses or an IP address and port number for internet addresses. Also, diffrent kinds of addresses have different sets of operations defined on them.

Internally, sockets use numerical addresses and port numbers, whereas human users and programmers may prefer names for these entities. The conversion of such names into numbers and vice versa involves resolving through lookup systems such as DNS. A host is usually identifeid by its name and has one or more addresses, IPv4, IPv6 or other possible addresses. Although a host can have multiple addresses, a socket can connect to only one address. A service can have a similar problem. One service, as identified by name, may be available on multiple ports. It is in general up to an application to make appropriate selections in a multitude of addresses, although sensible defaults may be provided by address objects.

1.1 TODO:

2 CLASSES

The following class diagram shows the classes and their relationships:

The top-level template classes are very similar to the standard iostream classes. The classes basic_sockstream, basic_isockstream, basic_osockstream and basic_sockbuf are almost the same as their basic_fstream, basic_ifstream, basic_ofstream and basic_filebuf counterparts. Just like the standard stream classes, these template classes use the character type and character traits as template parameters. Normal character and wide character variants are simply defined with typedefs, for example:

  typedef basic_sockbuf<char>      sockbuf;
  typedef basic_sockstream<char>   sockstream;
The key class in the hierarchy is the basic_sockbuf class that holds a close relation to the Socket class and performs the actual I/O operations. The sockbuf class inherits most of its functionality from the std::streambuf baseclass. The sockbuf overrides overflow() and underflow() members and provides the actual buffer space. Depending on the type of communication, two types of Socket objects are possible: Stream and Datagram.

The SocketAddress determines what a Socket connects to or listens to. For most Sockets, a SocketAddress basicly consists of a port and an IP address which are determined from the Service and Host for which the socket is intended. Only UNIX domain sockets are defined by a single pathname of the socket device. Depending on the address family that is used for the Socket Address, one of the three kinds of Socket Address is used to connect a socket: UNIX, IPv4 or IPv6. It is up to an application programmer to figure out where a Sockets connects to and create an appropriate type of SocketAddress to which a Socket can connect or listen.

Classes to help an application setup a Socket Address are Host and Service, which perform lookup functions as implemented in getaddrinfo(3).

3 SCENARIOS

3.1 Make a stream socket connected to a specific host and service

  1. Application creates a Host object with the desired hostname.
  2. Host object finds IP addresses and returns the list.
  3. Application selects one IP address from the list.
  4. Application creates a Service object with the desired name or port number.
  5. Service object determines a list of available port addresses.
  6. Application selects one service port from the list.
  7. Application creates an object derived from SocketAddres, using the selected Internet Address and Service.
  8. Application creates a Stream Socket object and tells it to connect to the Socket Address.

3.2 Setup a listening stream socket

  1. Application creates a Service object with the desired name or port number.
  2. Service object determines a list of available port addresses.
  3. Application selects one service port from the list.
  4. Application creates an object derived from SocketAddres, using the ANY Internet Address and Service.
  5. Application creates a Stream Socket object and tells it to listen on the Socket Address.

4 MEMBERS and METHODS

4.1 basic_sockstream

Derived from the std::basic_iostream<> template class.

4.1.1 Methods

basic_sockstream(StreamSocket)
Constructor for a stream to an existing (connected) stream socket.

4.2 basic_isockstream

Derived from the std::basic_istream<> template class.

4.2.1 Methods

basic_isockstream(StreamSocket)
Constructor for a stream to an existing (connected) stream socket.

4.3 basic_osockstream

Derived from the std::basic_ostream<> template class.

4.3.1 Methods

basic_osockstream(StreamSocket)
Constructor for a stream to an existing (connected) stream socket.

4.4 basic_sockbuf

The basic_sockbuf<> template class applies the functionality of the std::basic_streambuf to network sockets. The sockbuf class overrides a few streambuf virtual functions to implement input and output to the actual socket through a Socket object.

4.4.1 Members

sock
A Socket object that holds the actual socket.

4.4.2 Methods

connect(StreamSocket)
Connect the sockbuf to a Socket object.
close()
Close the UNIX file descriptor in the Socket.
overflow(int)
Override of the base class overflow function.
sync()
Override of the base class overflow function.
underflow()
Override of the base class underflow function.

4.5 Socket

The Socket represents the device through which the actual communication takes place. This class encapsulates the socket interface in the UNIX or Linux kernel. A Socket is itself an abstract base class from which two types of Socket are derived: A StreamSocket and a DatagramSocket. Each of these classes have special properties and only the common parts are defined in the Socket base class. Note that the actual socket is not closed on destruction of a Socket object. The Close() method must be called to close the socket's file descriptor. As a result, it is safe for Socket objects to be copied, for example when passing such an object as a parameter or return value.

4.5.1 Members

fd
The UNIX file descriptor of the socket in the kernel.

4.5.2 Methods

Socket()
Default contructor. Initializes members.
Listen(SocketAddress)
Creates a server socket. Implmented in derived classes.
Close()
Close the UNIX socket without destroying the object itself.

4.5.3 Exceptions

4.6 StreamSocket

Implements a socket of the SOCK_STREAM type. Note that a StreamSocket object is either listening for incoming connection requests or is connected to a peer socket.

4.6.1 Methods

Listen(SocketAddress)
Bind the socket to the address and put the socket in the listening state.
Connect(SocketAddress)
Make a connection to a server socket.
StreamSocket Accept()
Accept a client connection and return the new connected socket.
Read(void *, size_t)
Input data from the other side.
Write(void *, size_t)
Output data to the other side.

4.7 DatagramSocket

Implements a socket of the SOCK_DGRAM type.

4.7.1 Methods

Listen(SocketAddress)
Bind the socket to the address and wait for incoming messages.
SendTo()
Send data to another socket.
ReceiveFrom()
Receive data from another socket.

4.8 SocketAddress

The abstract base class for all kinds of socket addresses. The SocketAddress class provides an interface for binding and connecting sockets.

4.8.1 Methods

address_family()
Return the address family of the socket address. Since this function is pure virtual, it must be overridden in a derived class. The dervied classes described in following sections will return AF_UNIX, AF_INET or AF_INET6.
get_sockaddr()
Return the sockaddr pointer that can be used by the bind(2) or connect(2) system calls.
get_socklen()
Return the length of the sockaddr structure that can be used by the bind(2) or connect(2) system calls.

4.8.2 Exceptions

4.9 UNIXSocketAddress

Implementation of SocketAddress for UNIX domain sockets.

4.9.1 Methods

UNIXSocketAddress(String)
The constructor.

4.10 IPv4SocketAddress

Implementation of SocketAddress for IPv4 domain sockets.

4.10.1 Methods

IPSocketAddress(InternetAddress, Port)
The constructor.

4.11 IPv6SocketAddress

Implementation of SocketAddress for IPv6 domain sockets.

4.12 Service

A Service is determined by its name, port number and service type (stream or datagram).

4.12.1 Methods

Service()
The overloaded constructor can accept a string with a service name or a port number.
FindAddress()
Find all port numbers of the service, given its name. Since a single service can be available on more than one port, this creates a list of port numbers.
FindName()
Find the name of the service that belongs to the first port number in the list of port numbers.

4.12.2 Exceptions

4.13 Port

A Port is determined by its port number and socket type (stream, datagram, etcetera).

4.13.1 Members

port
The port number in network byte order.
sockettype
The type of socket on which the service is available. Can be stream (SOCK_STREAM), datagram (SOCK_DGRAM) or any other type as described in socket(2).

4.13.2 Methods

get_port()
The port number in network byte order.
get_sockettype()
The type of socket on which the service is available.
operator unsigned short()
The port number in host byte order.
operator ==()
operator !=()

4.13.3 Exceptions

4.14 Host

4.14.1 Methods

Host()
The overloaded constructor can accept a string with a hostname or an InternetAddress object.
FindAddress()
Find all network addresses of the host, given its name. Since a single host can hold multiple IP addresses, this creates a list of InternetAddress objects.
FindName()
Find the name of the host that belongs to the first IP address in the list of InternetAddress objects.

4.14.2 Exceptions

4.15 InternetAddress

An InternetAddress object holds an IP address which can be either an IPv4 address or an IPv6 address. Its main purpose is to perform the conversion between addresses in network byte order end textual representations of an IP address.

4.16 Members

af
The address family, AF_UNSPEC, AF_INET of AF_INET6
inet_addr
The address itself, in network byte order. Large enough to hold a IPv6 address (16 bytes).

4.17 Methods

InternetAddress()
Constructor creates the IP address from a variaty of forms, including conversion from a String. The address family (AF_INET or AF_INET6) is determined from the argument passed to the constructor. Possible argument types are struct addrinfo as used by getaddrinfo(3), struct in_addr, struct in6_addr and String With the IP address in character string form, the address family is determined by the presence of colon (:) characters in the IP address, as these can only occur in IPv6 addresses. See also inet_pton(3)
address_family()
Returns the address family to which the IP address belongs. Either AF_INET of AF_INET6.
String()
Converts the IP address to textual form in a manner like inet_ntop(3).
get_in_addr()
Returns an IPv4 address in struct in_addr format.
get_in6_addr()
Returns an IPv6 address in struct in6_addr format.
operator ==()
Two internet addresses are equal if both the address family and the address itself of the internet addresses are equal.
operator !=()
The opposite of the == operator.

4.18 Exceptions