| 1 |
#include <OSGConfig.h> |
|---|
| 2 |
|
|---|
| 3 |
using namespace OSG; |
|---|
| 4 |
|
|---|
| 5 |
/*! \page PageBaseSocket Socket |
|---|
| 6 |
|
|---|
| 7 |
Socket baseclass. The Socket class wraps a socket descriptor. This |
|---|
| 8 |
class has no additional state variables. It is only h handle to the |
|---|
| 9 |
underlaying descriptor. Class createion and destruction has no |
|---|
| 10 |
influence to any descriptor. Use open to assign a descriptor and |
|---|
| 11 |
close to remove it from the system. If this class is copied, then |
|---|
| 12 |
there are to classes which uses the same descriptor. This is |
|---|
| 13 |
ok until you call close for one of this classes. |
|---|
| 14 |
One purpose of this implementation is to hide the differences between |
|---|
| 15 |
Windows and Unix sockets. Calls to this class should behave equally |
|---|
| 16 |
on all systems. As a result, some methods will not work as an |
|---|
| 17 |
experienced Windows ore Unix programmer maight expect. Please refere |
|---|
| 18 |
to the function docu to get details about this. |
|---|
| 19 |
|
|---|
| 20 |
Stream sockets |
|---|
| 21 |
|
|---|
| 22 |
A stream socket is an endpoint for a reliable point to point |
|---|
| 23 |
communication. The following example code shows, how to establish a |
|---|
| 24 |
stream socket connection. |
|---|
| 25 |
|
|---|
| 26 |
<PRE> |
|---|
| 27 |
// server code |
|---|
| 28 |
StreamSocket socket,client; |
|---|
| 29 |
socket.open(); |
|---|
| 30 |
socket.bind(SocketAddress(SocketAddress::ANY,12345)); |
|---|
| 31 |
client=socket.accept(); |
|---|
| 32 |
client.send(buffer,100); |
|---|
| 33 |
client.close(); |
|---|
| 34 |
socket.close(); |
|---|
| 35 |
|
|---|
| 36 |
// client code |
|---|
| 37 |
StreamSocket server; |
|---|
| 38 |
server.open(); |
|---|
| 39 |
server.connect(SocketAddress("localhost",12345)); |
|---|
| 40 |
server.recv(buffer,100); |
|---|
| 41 |
server.close(); |
|---|
| 42 |
</PRE> |
|---|
| 43 |
|
|---|
| 44 |
The method bind() assigns the socket to a given port and network |
|---|
| 45 |
device. If the network device is ANY, then the socket will accept |
|---|
| 46 |
connections from all network interfaces. If the port number is zero, |
|---|
| 47 |
then a free port is assigned. In the above example, the socket will |
|---|
| 48 |
accept incoming connections at each interface on the port |
|---|
| 49 |
12345. StreamSocket::accept() waits for a incoming connection. For |
|---|
| 50 |
each incoming connection a new socket object will be created. With |
|---|
| 51 |
send and recv data can be transferred over the connection. By default |
|---|
| 52 |
all calls will block until the operation has finished. |
|---|
| 53 |
|
|---|
| 54 |
Datagram sockets |
|---|
| 55 |
|
|---|
| 56 |
Datagram sockets are not connection orientated. There is no connect or |
|---|
| 57 |
accept methods for datagram sockets. You have to provide a destination |
|---|
| 58 |
address for each send and will get a source address for each recv |
|---|
| 59 |
call. There is no guarantee that packages will arrive and there is no |
|---|
| 60 |
guarantee for the order in which the package will arrive. The followin |
|---|
| 61 |
code shows how to wait for incoming packages at port 22222. |
|---|
| 62 |
|
|---|
| 63 |
<PRE> |
|---|
| 64 |
SocketAddress client; |
|---|
| 65 |
DgramSocket socket; |
|---|
| 66 |
socket.open(); |
|---|
| 67 |
socket.bind(SocketAddress(SocketAddress::ANY,22222)) |
|---|
| 68 |
socket.recvFrom(buffer,100,client); |
|---|
| 69 |
socket.close(); |
|---|
| 70 |
</PRE> |
|---|
| 71 |
|
|---|
| 72 |
This is the code to send the package. This is a simple example. If the |
|---|
| 73 |
package gets lost for example because the server is not started, then |
|---|
| 74 |
this code wont work. If your application relays on reliable data |
|---|
| 75 |
transmission, then StreamSockets should be used. |
|---|
| 76 |
|
|---|
| 77 |
<PRE> |
|---|
| 78 |
DgramSocket sock; |
|---|
| 79 |
SocketAddress server; |
|---|
| 80 |
socket.open(); |
|---|
| 81 |
socket.sendTo("hallo",100,SocketAddress("localhost",22222)); |
|---|
| 82 |
socket.close(); |
|---|
| 83 |
</PRE> |
|---|
| 84 |
|
|---|
| 85 |
Exceptions: |
|---|
| 86 |
|
|---|
| 87 |
All socket methods will throw exceptions if the desired function could |
|---|
| 88 |
not be finished. All socket related exceptions are derived from the |
|---|
| 89 |
SocketException class. All socket calls should be enclosed in |
|---|
| 90 |
try/catch blocks. For example, if you want to check if a connect |
|---|
| 91 |
operation was successful then you should use the following code. |
|---|
| 92 |
|
|---|
| 93 |
<PRE> |
|---|
| 94 |
try |
|---|
| 95 |
{ |
|---|
| 96 |
server..connect(SocketAddress("localhost",12345)); |
|---|
| 97 |
} |
|---|
| 98 |
catch(SocketException &e) |
|---|
| 99 |
{ |
|---|
| 100 |
SFATAL << "Unable to connect to server:" << e.what() << endl; |
|---|
| 101 |
} |
|---|
| 102 |
</PRE> |
|---|
| 103 |
|
|---|
| 104 |
Each exceptions contains the system error text that causes the error |
|---|
| 105 |
situation. This text can be accessed by SocketException::what(). The |
|---|
| 106 |
text is given as an std:string object. |
|---|
| 107 |
|
|---|
| 108 |
Broadcast Messages |
|---|
| 109 |
|
|---|
| 110 |
Broadcast packages are a special case of datagram packages. Broadcast |
|---|
| 111 |
packages are send to each host in a network. For broadcasting packages |
|---|
| 112 |
a special address type is used. For example with the address |
|---|
| 113 |
SocketAddress(SocketAddress::BROADCAST,2345) packages will be send to each |
|---|
| 114 |
host on port number 2345. Equal to normal datagram sockets, broadcast |
|---|
| 115 |
packages are transmitted not reliable. |
|---|
| 116 |
|
|---|
| 117 |
Multicast Messages |
|---|
| 118 |
|
|---|
| 119 |
With multicast it is possible to send packages to more then one |
|---|
| 120 |
destination. In contrast to broadcast the package is not send to all |
|---|
| 121 |
hosts but only to those hosts that have joined a multicast group. A |
|---|
| 122 |
multicast group is specified with special IP addresses |
|---|
| 123 |
(224.xxx.xxx.xxx). To write a package to the multicast group |
|---|
| 124 |
224.22.33.33 at port 4444 you could use |
|---|
| 125 |
|
|---|
| 126 |
<PRE> |
|---|
| 127 |
socket.sendTo(buffer,100,SocketAddress("224.22.33.44",4444) |
|---|
| 128 |
</PRE> |
|---|
| 129 |
|
|---|
| 130 |
The receive has to join this group. The following examples shows how |
|---|
| 131 |
to join and leave multicast groups. It is possible to join more then |
|---|
| 132 |
one group. |
|---|
| 133 |
|
|---|
| 134 |
<PRE> |
|---|
| 135 |
socket.bind(SocketAddress(SocketAddress::ANY,4444)); |
|---|
| 136 |
socket.join(SocketAddress("224.22.33.44")); |
|---|
| 137 |
socket.join(SocketAddress("224.0.0.52")); |
|---|
| 138 |
socket.join(SocketAddress("224.0.0.53")); |
|---|
| 139 |
socket.leave(SocketAddress("224.0.0.52")); |
|---|
| 140 |
</PRE> |
|---|
| 141 |
|
|---|
| 142 |
With multicast groups you also have to bind your socket to a network |
|---|
| 143 |
device and port. In the example above only those packages are received |
|---|
| 144 |
that are send to port 4444. With multicast it often happens, that you |
|---|
| 145 |
have more then one member of a multicast group on a single host. If |
|---|
| 146 |
you try to call bind for the same port multiple times, then you will |
|---|
| 147 |
get socket exceptions. To be able to assign more then one process to |
|---|
| 148 |
the same port you have to call socket.setReusePort(true) before the |
|---|
| 149 |
call to bind. |
|---|
| 150 |
|
|---|
| 151 |
It is possible set the network device that is used to send |
|---|
| 152 |
multicast packages. By default the system uses the first device |
|---|
| 153 |
that is capable to send multicast packages. |
|---|
| 154 |
|
|---|
| 155 |
<PRE> |
|---|
| 156 |
socket.setInterface(SocketAddress("192.168.10.1")); |
|---|
| 157 |
</PRE> |
|---|
| 158 |
|
|---|
| 159 |
Nonblocking IO |
|---|
| 160 |
|
|---|
| 161 |
In many applications it is not possible or not wanted to block |
|---|
| 162 |
execution until an accept() or recv() call has finished. Each socket |
|---|
| 163 |
has methods to ask if it is possible to read or write data without |
|---|
| 164 |
blocking. The followin examples shows how to wait for data without |
|---|
| 165 |
blocking. |
|---|
| 166 |
|
|---|
| 167 |
<UL> |
|---|
| 168 |
<LI>socket.waitReadable(0): Don't wait, returns true if data is |
|---|
| 169 |
available otherwise it returns false. |
|---|
| 170 |
<LI>socket.waitReadable(0.5): If data arrives in the next .5 seconds |
|---|
| 171 |
then true is returned. Otherwise false is returned. |
|---|
| 172 |
<LI>socket.waitReadable(-1): Wait until data is available and then |
|---|
| 173 |
return true. This function call is equal to a blocking read. |
|---|
| 174 |
<LI>socket.waitWritable(10): If the socket is able to send data in the |
|---|
| 175 |
next 10 seconds, then true is returned. Otherwise false. |
|---|
| 176 |
</UL> |
|---|
| 177 |
|
|---|
| 178 |
With this simple interface it is possible to wait a specified time for |
|---|
| 179 |
incoming or outgoing data. But it is only possible to wait for exactly one |
|---|
| 180 |
socket. If it is necessary to wait for more then one socket then the |
|---|
| 181 |
Selection class could be used. A selection specifies for each socket |
|---|
| 182 |
for what kind of event the system should wait. |
|---|
| 183 |
|
|---|
| 184 |
<PRE> |
|---|
| 185 |
SocketSelection s; |
|---|
| 186 |
s.setRead(socket1); |
|---|
| 187 |
s.setRead(socket2); |
|---|
| 188 |
s.select(.1); |
|---|
| 189 |
if(s.isSetRead(sock1)) |
|---|
| 190 |
socket 1 is readable |
|---|
| 191 |
if(s.isSetRead(sock2)) |
|---|
| 192 |
socket 1 is readable |
|---|
| 193 |
</PRE> |
|---|
| 194 |
|
|---|
| 195 |
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). |
|---|
| 196 |
|
|---|
| 197 |
IO-Buffers |
|---|
| 198 |
|
|---|
| 199 |
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. |
|---|
| 200 |
|
|---|
| 201 |
*/ |
|---|