VR-Link JAVA API Documentation
 All Classes Namespaces Files Functions Variables Enumerator Pages
8.3 - Configuring Your Connection to the DIS Network

Table of Contents

As described in 4.2 - Connecting to Exercises, a DtExerciseConn serves as an application's connection to a DIS or HLA exercise.

The DIS version is defined in dExerciseConn.h.

A DIS DtExerciseConn uses a DtInetSocket (defined in vlInetSocket.h) as its low-level interface to a virtual network. DtInetSocket is an abstract class whose virtual functions send() and recv(), along with their variants (described in the header file), allow you to send and receive a packet of data among applications without regard to the actual communication mechanism used. Subclasses of DtInetSocket implement different methods of communication and take different configuration parameters.

8.3.1 DtExerciseConn Constructors

Two of DtExerciseConn's constructors create a DtInetSocket based on their arguments; the other takes an existing DtInetSocket as an argument.

All constructors take an exercise ID as an argument. The exercise ID is copied into the header of outgoing PDUs when sendStamped() is used, and is used for filtering incoming PDUs as well. Only those PDUs on the matching exercise are passed to the application by the exercise connection. If a DtExerciseConn's exercise ID is set to zero, it reads and processes PDUs from all exercises. However, PDUs should never be sent to exercise zero, so exercise ID zero should usually be used only in applications that are listen-only. Once a DtExerciseConn is constructed, you can change or examine the current exercise ID with setExerciseId() and exerciseId().

8.3.1.1 Standard Constructor

The standard DtExerciseConn constructor (described in 4.2.2 Creating an Exercise Connection for DIS) creates a DtDisSocket (vlDisSocket.h) to communicate directly to the network. The DtExerciseConn receives any unicast or broadcast packets destined for the computer on the specified port, and by default, sends packets to the broadcast address of the computer's primary network interface (when no address is specified in a call to send() or sendStamped()).

8.3.1.2 A Constructor that Takes A Destination Address

The second DtExerciseConn constructor is similar to the first, but in addition to the four arguments expected by the standard constructor, it takes a destination address. The destination address is used as the default IP address to which outgoing packets are sent. It can be a unicast, multicast, or broadcast address.

For example, to indicate that packets should be sent only to the computer with the address 207.86.232.1, do this:

DtExerciseConn(3000, DtInetAddr("207.86.232.1"));

In this case, we will still receive packets destined for our broadcast and unicast addresses.

8.3.1.3 Using A Secondary Network Device

The second constructor is also useful when you want to use a device other than a computer's primary network device. Pass the broadcast address associated with the desired device as the destination address.

Note
The two devices must be on different networks. There is no way for a UDP socket to distinguish between two devices on the same network.

8.3.1.4 A Constructor that Takes A Pointer to A DtInetSocket

The third DtExerciseConn constructor takes a pointer to a DtInetSocket, and thus gives you full control of how the socket is created. You can even derive your own type of DtInetSocket and pass an instance of it to a DtExerciseConn. (Perhaps you want to create a SharedMemorySocket.) In this case, the socket is not deleted by the DtExerciseConn object. Because you allocate it, it is your responsibility to delete it. However, you must not delete the DtInetSocket until after the DtExerciseConn has been destroyed.

Please see the following sections for more configuration information. Once a DtExerciseConn is constructed, its socket() member function will return a pointer to the socket it is using.

8.3.2 Configuring a DtDisSocket

The DtDisSocket class is a subclass of DtInetSocket, which can be passed into the DtExerciseConn constructor. It contains features that help to send and receive DIS PDU's.

If you are constructing a DtDisSocket, (vlDisSocket.h), several parameters may be passed in, but the only required parameter is the DtInetEndpoint, which describes the destination address and port of DIS PDU's sent. Other optional parameters are:

The flags argument is a bitwise OR of several options that are defined in vlInetSocket.h. The default is DtDefaultSockOpts, which is a bitwise OR of DtReadWrite, DtSockOptAllReuse, and DtSockOptNoDelay. This creates a socket that can read and write, can reuse addresses and ports, and has the no-delay option set. Please see the vlInetSocket.h class documentation for the definitions of these flags.

If a DtInetDevice is passed in, the socket binds to that device for reading. This is useful for multi-homed machines if you only want to read DIS PDU's from one network card. For instance, if you have two network cards with the addresses 1.1.1.1, and 192.168.0.1, and you are only interested in receiving PDU's from the 192.168.0.1 network, you can construct the socket as follows:

DtInetEndpoint endpoint(DtInetProto_UDP, DtInetAddr("192.168.255.255"),
3300);
DtInetDevice deviceToUse(DtInetAddr("192.168.0.1"));
DtDisSocket* sock = 0;
if (deviceToUse.isOk())
{
sock = new DtDisSocket(endpoint, 0, deviceToUse);
}

This causes the socket to only read from the 192.168.0.1 interface. If a NULL pointer is passed in, the socket binds to the "any" address, allowing it to receive any PDU's sent to the specified port.

8.3.3 Using Asynchronous IO

VR-Link supports asynchronous IO for DIS. (Asynchronous IO for HLA is handled by the RTI.) A socket with asynchronous IO enabled has all the functionality of DtInetSocket. However, it creates two threads that read and write to the network. The read thread reads packets from the network and places them on a queue. When an application reads a packet from the socket, it reads it from the queue. When an application writes to the network using asynchronous IO, it writes to a queue. The send thread reads the queue and sends packets to the network as soon as possible.

You create a socket that uses asynchronous IO just like you create a DtDisSocket.

The DIS version of DtExerciseConn can use asynchronous IO in either of the following ways:

Asynchronous IO is not faster, but if your simulation has well separated spikes of network traffic, it can help reduce dropped packets.

8.3.4 Subscribing to Multicast Addresses

DtExerciseConn allows subscription to one or more multicast addresses. Valid multicast addresses are those that lie between 224.0.0.0 and 239.255.255.255, but you should probably not use any that start with 224.0.0, to avoid potential conflict with addresses used by operating systems and network services.

Note
Not all platforms support multicast.

Interest in a particular multicast address is indicated using DtExerciseConn::addInterestInMcastAddr(). When a multicast group is no longer of interest, call subtractInterestInMcastAddr().

Different code modules can add and subtract interest in a particular group independently. As long as the number of calls to addInterest() outnumbers calls to subtractInterest() for a particular group, packets on that multicast address are received.

To send to a particular multicast address, include that address as the destAddr argument to send() or sendStamped().

You do not have to be subscribed to a multicast address to send to it.

If the destination address passed to a DtExerciseConn constructor is a multicast address, you do not need to call addInterest() for that address. You will automatically be subscribed.

Note
On many platforms, multicast subscription works on a per-host basis, rather than on a per-application basis. This means that if you have several applications listening to the same port on the same machine, and one of them subscribes to a particular multicast address, all of the applications will receive packets on that multicast address, even if they did not explicitly subscribe.

If there are several routers on your network between machines that are exchanging PDUs using multicast, you may need to increase the Time To Live (TTL) for outgoing multicast packets, to ensure that the packets are actually forwarded across the routers. You can do this with DtInetUdpSocket::setMcastTtlOption().

8.3.5 Filtering PDUs

A DtExerciseConn can instruct its DtDisSocket to filter out PDUs based on certain criteria. In this way, unwanted PDUs require no processing by the DtExerciseConn.

By default, packets that are not of an expected protocol version and packets whose exercise IDs do not match the exercise ID of the DtExerciseConn are filtered out. Expected protocol versions are those between the values of the global variables DtProtocolVersionToRecvMin and DtProtocolVersionToRecvMax, declared in pdu.h. These parameters default to 4 and 6 respectively. Table 3-1 lists the DIS version numbers.

In addition, the DtExerciseConn maintains a list of all PDU kinds in which it is interested. This includes all PDU kinds on which callbacks have been registered, as well as any PDU kinds in which an interest has been explicitly added using DtExerciseConn::

addInterestInPduKind(). (The subtractInterestInPduKind() function removes interest in a PDU kind.) The DtExerciseConn's DtInetSocket filters out all PDU kinds in which it has no interest. The DtPduKind enumeration is in disEnums.h.

You can turn filtering on and off with the functions DtExerciseConn::disableFiltering() and DtExerciseConn::enableFiltering().

8.3.6 Bundling and Unbundling PDU Packets

VR-Link supports bundling of multiple PDUs into a single network packet, and unbundling of such packets into their constituent PDUs.

Bundling is off by default, but can be turned on using the DtDisSocket::setBundling() member function. Pass to it the desired maximum size for a packet, along with some default values. When bundling is on, a sequence of packets passed to a socket's send member function (for example, from DtExerciseConn::sendStamped()), are concatenated together. The bundle is passed to DtDisSocket::sendTo() whenever a packet would push the bundle size beyond maxSize. A good choice for maxSize is the maximum size of the data portion of an ethernet packet: 1464 bytes. If you are using a networking scheme other than ethernet, use the maximum packet size for that scheme. Bundling is turned off by passing false as the second parameter to setBundling(). For example, to turn on bundling with a max size of 1464 bytes, you can call:

disSocket.setBundling(1464, true, 0, 0, 0, 0);

To turn it off, you can call:

disSocket.setBundling(0, false, 0, 0, 0, 0);
Note
If you turn on bundling, other participants in your simulation must be able to unbundle the packes.

You can force sending of the current bundle with DtDisSocket::flush(). If you are using bundling, call the flush() member function at the end of each simulation frame to ensure that all packets generated during a frame get sent before the next frame begins.

The isBundling() member function returns false if bundling is off, and the getMaxBundleSize() member function returns the maximum bundle size.

Unbundling is enabled by default, but it can be turned on or off by passing 0 or 1 to DtDisSocket::setUnbundling(). With unbundling on, when a packet arrives containing more than one PDU, successive calls to the receive function (the call made by DtExerciseConn:: netRead()) return successive PDUs from the packet. On the next call to receive after the last PDU from a packet has been returned, the first PDU from the next packet is returned.

If unbundling is disabled, but a bundled packet is received, all but the first PDU in the packet is ignored.

8.3.7 Sending Packets Using DtInetSocket

There are several ways to send packets with any DtInetSocket class. The header files of each socket class (vlInetSocket.h, vlInetUdpSocket.h, vlInetTcpSocket.h, and vlDisSocket.h) provide a description of each member function.

To send, the DtExerciseConn class uses either the send() or sendTo() member function of the DtInetSocket, depending on whether an address is passed into the DtExerciseConn::send() member function. The socket's send() member function returns the number of bytes sent, or -1 if the packets cannot be sent. If -1 is returned, the getLastError() or getLastErrorString() member function can be used to query which error was encountered.

Note
DtInetSockets do not know anything about byte swapping or PDU layout (with the exception of some knowledge of PDU header layout used for filtering). The data contained in the buffer passed to DtInetSocket's sending functions are the exact bytes that will go out onto the network.

8.3.8 Receiving Packets Using DtInetSocket

As with sending, there are several ways to receive packets with any DtInetSocket class. Please see the header files and class documentation for a description of each member function.

The DtExerciseConn uses the recv() member function to read the next packet available. The return status can be checked to determine the status of any of the receive calls.

[<< Working with Non-Standard PDUs] [Home] [Top of Page] [Intercepting Incoming Entity State PDUs >>]


Document ID: Generated on Fri Dec 2 02:42:08 EST 2016 from SVN revision 171416
Copyright © 2005-2016 VT MÄK. All Rights Reserved (www.mak.com)