Socket

Socket baseclass. The Socket class wraps a socket descriptor. This class has no additional state variables. It is only h handle to the underlaying descriptor. Class createion and destruction has no influence to any descriptor. Use open to assign a descriptor and close to remove it from the system. If this class is copied, then there are to classes which uses the same descriptor. This is ok until you call close for one of this classes. One purpose of this implementation is to hide the differences between Windows and Unix sockets. Calls to this class should behave equally on all systems. As a result, some methods will not work as an experienced Windows ore Unix programmer maight expect. Please refere to the function docu to get details about this.

Stream sockets

A stream socket is an endpoint for a reliable point to point communication. The following example code shows, how to establish a stream socket connection.

// server code
StreamSocket socket,client;
socket.open();
socket.bind(SocketAddress(SocketAddress::ANY,12345));
client=socket.accept();
client.send(buffer,100);
client.close();
socket.close();

// client code
StreamSocket server;
server.open();
server.connect(SocketAddress("localhost",12345));
server.recv(buffer,100);
server.close();

The method bind() assigns the socket to a given port and network device. If the network device is ANY, then the socket will accept connections from all network interfaces. If the port number is zero, then a free port is assigned. In the above example, the socket will accept incoming connections at each interface on the port 12345. StreamSocket::accept() waits for a incoming connection. For each incoming connection a new socket object will be created. With send and recv data can be transferred over the connection. By default all calls will block until the operation has finished.

Datagram sockets

Datagram sockets are not connection orientated. There is no connect or accept methods for datagram sockets. You have to provide a destination address for each send and will get a source address for each recv call. There is no guarantee that packages will arrive and there is no guarantee for the order in which the package will arrive. The followin code shows how to wait for incoming packages at port 22222.

SocketAddress client;
DgramSocket socket;
socket.open();
socket.bind(SocketAddress(SocketAddress::ANY,22222))
socket.recvFrom(buffer,100,client);
socket.close();

This is the code to send the package. This is a simple example. If the package gets lost for example because the server is not started, then this code wont work. If your application relays on reliable data transmission, then StreamSockets should be used.

DgramSocket sock;
SocketAddress server;
socket.open();
socket.sendTo("hallo",100,SocketAddress("localhost",22222));
socket.close();

Exceptions:

All socket methods will throw exceptions if the desired function could not be finished. All socket related exceptions are derived from the SocketException class. All socket calls should be enclosed in try/catch blocks. For example, if you want to check if a connect operation was successful then you should use the following code.

try
{
    server..connect(SocketAddress("localhost",12345));
}
catch(SocketException &e)
{
    SFATAL << "Unable to connect to server:" << e.what() << endl;
}

Each exceptions contains the system error text that causes the error situation. This text can be accessed by SocketException::what(). The text is given as an std:string object.

Broadcast Messages

Broadcast packages are a special case of datagram packages. Broadcast packages are send to each host in a network. For broadcasting packages a special address type is used. For example with the address SocketAddress(SocketAddress::BROADCAST,2345) packages will be send to each host on port number 2345. Equal to normal datagram sockets, broadcast packages are transmitted not reliable.

Multicast Messages

With multicast it is possible to send packages to more then one destination. In contrast to broadcast the package is not send to all hosts but only to those hosts that have joined a multicast group. A multicast group is specified with special IP addresses (224.xxx.xxx.xxx). To write a package to the multicast group 224.22.33.33 at port 4444 you could use

socket.sendTo(buffer,100,SocketAddress("224.22.33.44",4444) 

The receive has to join this group. The following examples shows how to join and leave multicast groups. It is possible to join more then one group.

socket.bind(SocketAddress(SocketAddress::ANY,4444));
socket.join(SocketAddress("224.22.33.44"));
socket.join(SocketAddress("224.0.0.52"));
socket.join(SocketAddress("224.0.0.53"));
socket.leave(SocketAddress("224.0.0.52"));

With multicast groups you also have to bind your socket to a network device and port. In the example above only those packages are received that are send to port 4444. With multicast it often happens, that you have more then one member of a multicast group on a single host. If you try to call bind for the same port multiple times, then you will get socket exceptions. To be able to assign more then one process to the same port you have to call socket.setReusePort(true) before the call to bind.

It is possible set the network device that is used to send multicast packages. By default the system uses the first device that is capable to send multicast packages.

socket.setInterface(SocketAddress("192.168.10.1"));

Nonblocking IO

In many applications it is not possible or not wanted to block execution until an accept() or recv() call has finished. Each socket has methods to ask if it is possible to read or write data without blocking. The followin examples shows how to wait for data without blocking.

With this simple interface it is possible to wait a specified time for incoming or outgoing data. But it is only possible to wait for exactly one socket. If it is necessary to wait for more then one socket then the Selection class could be used. A selection specifies for each socket for what kind of event the system should wait.

SocketSelection s;
s.setRead(socket1);
s.setRead(socket2);
s.select(.1);
if(s.isSetRead(sock1)) 
   socket 1 is readable
if(s.isSetRead(sock2)) 
   socket 1 is readable

A call of selection.select(seconds) waits the given number of seconds for the events set with setRead() or serWrite(). It returns after the first occurrence of an event. If no events occur in the given periode then 0 is returned. Otherwise the number of readable and writable sockets is returned. The method select() modifies the selection object. You have to call setRead() and setWrite() for each time, you want to call select(). If the SocketSelection is constant, then you can use an other version of select. With s.select(seconds,rs) s will not be modified. The result will be set into the SocketSelection rs. You have to call rs.isReadable(sock) instead of s.isReadable(sock).

IO-Buffers

If data should be read from more then one socket, then the performance could be improved by not reading from the first socket that provides data but from that socket with the most data in the input buffer. With socket.getAvailable() the number of bytes in the input buffer could be retrieved. In addition the Socket class provides the functions setWriteBufferSize and setReadBufferSize set the size of input and output buffers. Current sizes can be retrieved with getReadBufferSize and getWriteBufferSize.


Generated on Mon Mar 17 11:10:26 2008 for OpenSG by  doxygen 1.5.5