Java Network Programming (3rd ed) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Java Network Programming (3rd ed) [Electronic resources] - نسخه متنی

Harold, Elliotte Rusty

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








13.3 The DatagramSocket Class


To send or receive a
DatagramPacket, you must open a datagram socket.
In Java, a datagram socket is created and accessed through the
DatagramSocket class:

public class DatagramSocket extends Object

All datagram sockets are bound to a local port, on which they listen
for incoming data and which they place in the header of outgoing
datagrams. If you're writing a client, you
don't care what the local port is, so you call a
constructor that lets the system assign an unused port (an anonymous
port). This port number is placed in any outgoing datagrams and will
be used by the server to address any response datagrams. If
you're writing a server, clients need to know on
which port the server is listening for incoming datagrams; therefore,
when a server constructs a DatagramSocket, it
specifies the local port on which it will listen. However, the
sockets used by clients and servers are otherwise identical: they
differ only in whether they use an anonymous (system-assigned) or a
well-known port. There's no distinction between
client sockets and server sockets, as there is with TCP;
there's no such thing as a
DatagramServerSocket.


13.3.1 The Constructors


The DatagramSocket
constructors are used in different situations, much like the
DatagramPacket constructors. The first constructor
opens a datagram socket on an anonymous local port. The second
constructor opens a datagram socket on a well-known local port that
listens to all local network interfaces. The third constructor opens
a datagram socket on a well-known local port on a specific network
interface. Java 1.4 adds a constructor that allows this network
interface and port to be specified with a
SocketAddress. Java 1.4 also adds a protected
constructor that allows you to change the implementation class. All
five constructors deal only with the local address and port. The
remote address and port are stored in the
DatagramPacket, not the
DatagramSocket. Indeed, one
DatagramSocket can send and receive datagrams from
multiple remote hosts and ports.

13.3.1.1 public DatagramSocket( ) throws SocketException


This constructor creates a socket that is bound to an anonymous port.
For example:

try {
DatagramSocket client = new DatagramSocket( );
// send packets...
}
catch (SocketException ex) {
System.err.println(ex);
}

You would use this constructor in a client that initiates a
conversation with a server. In this scenario, you
don't care what port the socket is bound to, because
the server will send its response to the port from which the datagram
originated. Letting the system assign a port means that you
don't have to worry about finding an unused port. If
for some reason you need to know the local port, you can find out
with the getLocalPort( ) method described later in
this chapter.

The same socket can receive the datagrams that a server sends back to
it. A SocketException is thrown if the socket
can't be created. It's unusual for
this constructor to throw an exception; it's hard to
imagine situations in which the socket could not be opened, since the
system gets to choose the local port.

13.3.1.2 public DatagramSocket(int port) throws SocketException


This constructor creates a socket that listens for incoming datagrams
on a particular port, specified by the port
argument. Use this constructor to write a server that listens on a
well-known port; if servers listened on anonymous ports, clients
would not be able to contact them. A
SocketException is thrown if the socket
can't be created. There are two common reasons for
the constructor to fail: the specified port is already occupied, or
you are trying to connect to a port below 1,024 and you
don't have sufficient privileges (i.e., you are not
root on a Unix system; for better or worse, other platforms allow
anyone to connect to low-numbered ports).

TCP ports and UDP ports are not related. Two unrelated servers or
clients can use the same port number if one uses UDP and the other
uses TCP. Example 13-2 is a port scanner that looks
for UDP ports in use on the local host. It decides that the port is
in use if the DatagramSocket constructor throws an
exception. As written, it looks at ports from 1,024 and up to avoid
Unix's requirement that it run as root to bind to
ports below 1,024. You can easily extend it to check ports below
1,024, however, if you have root access or are running it on Windows.


Example 13-2. Look for local UDP ports


import java.net.*;
public class UDPPortScanner {
public static void main(String[] args) {
for (int port = 1024; port <= 65535; port++) {
try {
// the next line will fail and drop into the catch block if
// there is already a server running on port i
DatagramSocket server = new DatagramSocket(port);
server.close( );
}
catch (SocketException ex) {
System.out.println("There is a server on port " + port + ".");
} // end try
} // end for
}
}

The speed at which UDPPortScanner runs depends
strongly on the speed of your machine and its UDP implementation.
I've clocked Example 13-2 at as
little as two minutes on a moderately powered SPARCstation, under 12
seconds on a 1Ghz TiBook, about 7 seconds on a 1.4GHz Athlon system
running Linux, and as long as an hour on a PowerBook 5300 running
MacOS 8. Here are the results from the Linux workstation on which
much of the code in this book was written:

% java UDPPortScanner
There is a server on port 2049.
There is a server on port 32768.
There is a server on port 32770.
There is a server on port 32771.

The first port, 2049, is an NFS server. The high-numbered ports in
the 30,000 range are Remote Procedure Call (RPC) services. Along with
RPC, common protocols that use UDP include NFS, TFTP, and FSP.

It's much harder to scan UDP ports on a remote
system than to scan for remote TCP ports. Whereas
there's always some indication that a listening
port, regardless of application layer protocol, has received your TCP
packet, UDP provides no such guarantees. To determine that a UDP
server is listening, you have to send it a packet it will recognize
and respond to.

13.3.1.3 public DatagramSocket(int port, InetAddress interface) throws SocketException


This constructor is primarily used on multihomed hosts; it creates a
socket that listens for incoming datagrams on a specific port and
network interface. The port argument is the port
on which this socket listens for datagrams. As with TCP sockets, you
need to be root on a Unix system to create a
DatagramSocket on a port below 1,024. The
address argument is an
InetAddress object matching one of the
host's network addresses. A
SocketException is thrown if the socket
can't be created. There are three common reasons for
this constructor to fail: the specified port is already occupied, you
are trying to connect to a port below 1,024 and
you're not root on a Unix system, or
address is not the address of one of the
system's network interfaces.

13.3.1.4 public DatagramSocket(SocketAddress interface) throws SocketException // Java 1.4


This constructor is similar to the previous one except that the
network interface address and port are read from a
SocketAddress. For example, this code fragment
creates a socket that only listens on the local loopback address:

SocketAddress address = new InetSocketAddress("127.0.0.1", 9999);
DatagramSocket socket = new DatagramSocket(address);

13.3.1.5 protected DatagramSocket(DatagramSocketImpl impl) throws SocketException // Java 1.4


This constructor enables subclasses to provide their own
implementation of the UDP protocol, rather than blindly accepting the
default. Unlike sockets created by the other four constructors, this
socket is not initially bound to a port. Before using it you have to
bind it to a SocketAddress using the
bind( ) method, which is also new in Java 1.4:

public void bind(SocketAddress addr) throws SocketException

You can pass null to this method, binding the socket to any available
address and port.


13.3.2 Sending and Receiving Datagrams


The primary task of the
DatagramSocket class is to send and receive UDP
datagrams. One socket can both send and receive. Indeed, it can send
and receive to and from multiple hosts at the same time.

13.3.2.1 public void send(DatagramPacket dp) throws IOException


Once a DatagramPacket is created and a
DatagramSocket is constructed, send the packet by
passing it to the socket's send() method. For example, if
theSocket is a DatagramSocket
object and theOutput is a
DatagramPacket object, send
theOutput using theSocket like
this:

theSocket.send(theOutput);

If there's a problem sending the data, an
IOException may be thrown. However, this is less
common with DatagramSocket than
Socket or ServerSocket, since
the unreliable nature of UDP means you won't get an
exception just because the packet doesn't arrive at
its destination. You may get an IOException if
you're trying to send a larger datagram than the
host's native networking software supports, but then
again you may not. This depends heavily on the native UDP software in
the OS and the native code that interfaces between this and
Java's DatagramSocketImpl class.
This method may also throw a SecurityException if
the SecurityManager won't let you
communicate with the host to which the packet is addressed. This is
primarily a problem for applets and other remotely loaded code.

Example 13-3 is a UDP-based discard client. It reads
lines of user input from System.in and sends them
to a discard server, which simply discards all the data. Each line is
stuffed in a DatagramPacket. Many of the simpler
Internet protocols, such as discard, have both TCP and UDP
implementations.


Example 13-3. A UDP discard client


import java.net.*;
import java.io.*;
public class UDPDiscardClient {
public final static int DEFAULT_PORT = 9;
public static void main(String[] args) {
String hostname;
int port = DEFAULT_PORT;
if (args.length > 0) {
hostname = args[0];
try {
port = Integer.parseInt(args[1]);
}
catch (Exception ex) {
// use default port
}
}
else {
hostname = "localhost";
}
try {
InetAddress server = InetAddress.getByName(hostname);
BufferedReader userInput
= new BufferedReader(new InputStreamReader(System.in));
DatagramSocket theSocket = new DatagramSocket( );
while (true) {
String theLine = userInput.readLine( );
if (theLine.equals(".")) break;
byte[] data = theLine.getBytes( );
DatagramPacket theOutput
= new DatagramPacket(data, data.length, server, port);
theSocket.send(theOutput);
} // end while
} // end try
catch (UnknownHostException uhex) {
System.err.println(uhex);
}
catch (SocketException sex) {
System.err.println(sex);
}
catch (IOException ioex) {
System.err.println(ioex);
}
} // end main
}

The UDPDiscardClient class should look familiar.
It has a single static field, DEFAULT_PORT, which
is set to the standard port for the discard protocol (port 9), and a
single method, main( ). The main() method reads a hostname from the command line and
converts that hostname to the InetAddress object
called server. A BufferedReader
is chained to System.in to read user input from
the keyboard. Next, a DatagramSocket object called
theSocket is constructed. After creating the
socket, the program enters an infinite while loop
that reads user input line by line using readLine(). We are careful, however, to use only readLine(
)
to read data from the console, the one place where it is
guaranteed to work as advertised. Since the discard protocol deals
only with raw bytes, we can ignore character encoding issues.

In the while loop, each line is converted to a
byte array using the getBytes( ) method, and the
bytes are stuffed in a new DatagramPacket,
theOutput. Finally, theOutput
is sent over theSocket, and the loop continues. If
at any point the user types a period on a line by itself, the program
exits. The DatagramSocket constructor may throw a
SocketException, so that needs to be caught.
Because this is a discard client, we don't need to
worry about data coming back from the server.

13.3.2.2 public void receive(DatagramPacket dp) throws IOException


This method receives a single UDP datagram
from the network and stores it in the preexisting
DatagramPacket object dp. Like
the accept( ) method in the
ServerSocket class, this method blocks the calling
thread until a datagram arrives. If your program does anything
besides wait for datagrams, you should call receive() in a separate thread.

The datagram's buffer should be large enough to hold
the data received. If not, receive( ) places as
much data in the buffer as it can hold; the rest is lost. It may be
useful to remember that the maximum size of the data portion of a UDP
datagram is 65,507 bytes. (That's the 65,536-byte
maximum size of an IP datagram minus the 20-byte size of the IP
header and the 8-byte size of the UDP header.) Some application
protocols that use UDP further restrict the maximum number of bytes
in a packet; for instance, NFS uses a maximum packet size of 8,192
bytes.

If there's a problem receiving the data, an
IOException may be thrown. In practice, this is
rare. Unlike send( ), this method does not throw a
SecurityException if an applet receives a datagram
from other than the applet host. However, it will silently discard
all such packets. (This behavior prevents a denial-of-service attack
against applets that receive UDP datagrams.)

Example 13-4 shows a UDP discard server that receives
incoming datagrams. Just for fun, it logs the data in each datagram
to System.out so that you can see
who's sending what to your discard server.


Example 13-4. The UDPDiscardServer


import java.net.*;
import java.io.*;
public class UDPDiscardServer {
public final static int DEFAULT_PORT = 9;
public final static int MAX_PACKET_SIZE = 65507;
public static void main(String[] args) {
int port = DEFAULT_PORT;
byte[] buffer = new byte[MAX_PACKET_SIZE];
try {
port = Integer.parseInt(args[0]);
}
catch (Exception ex) {
// use default port
}
try {
DatagramSocket server = new DatagramSocket(port);
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
try {
server.receive(packet);
String s = new String(packet.getData( ), 0, packet.getLength( ));
System.out.println(packet.getAddress( ) + " at port "
+ packet.getPort( ) + " says " + s);
// reset the length for the next packet
packet.setLength(buffer.length);
}
catch (IOException ex) {
System.err.println(ex);
}
} // end while
} // end try
catch (SocketException ex) {
System.err.println(ex);
} // end catch
} // end main
}

This is a simple class with a single method, main(). It reads the port the server listens to from the command
line. If the port is not specified on the command line, it listens on
port 9. It then opens a DatagramSocket on that
port and creates a DatagramPacket with a
65,507-byte bufferlarge enough to receive any possible packet.
Then the server enters an infinite loop that receives packets and
prints the contents and the originating host on the console. A
high-performance discard server would skip this step. As each
datagram is received, the length of packet is set
to the length of the data in that datagram. Consequently, as the last
step of the loop, the length of the packet is reset to the maximum
possible value. Otherwise, the incoming packets would be limited to
the minimum size of all previous packets. You can run the discard
client on one machine and connect to the discard server on a second
machine to verify that the network is working.

13.3.2.3 public void close( )


Calling a DatagramSocket object's
close( ) method frees the port occupied by that
socket. For example:

try {
DatagramSocket server = new DatagramSocket( );
server.close( );
}
catch (SocketException ex) {
System.err.println(ex);
}

It's never a bad idea to close a
DatagramSocket when you're
through with it; it's particularly important to
close an unneeded socket if the program will continue to run for a
significant amount of time. For example, the close() method was essential in Example 13-2,
UDPPortScanner: if this program did not close the
sockets it opened, it would tie up every UDP port on the system for a
significant amount of time. On the other hand, if the program ends as
soon as you're through with the
DatagramSocket, you don't need to
close the socket explicitly; the socket is automatically closed upon
garbage collection. However, Java won't run the
garbage collector just because you've run out of
ports or sockets, unless by lucky happenstance you run out of memory
at the same time. Closing unneeded sockets never hurts and is good
programming practice.

13.3.2.4 public int getLocalPort( )


A DatagramSocket's
getLocalPort( ) method returns an
int that represents the local port on which the
socket is listening. Use this method if you created a
DatagramSocket with an anonymous port and want to
find out what port the socket has been assigned. For example:

try {
DatagramSocket ds = new DatagramSocket( );
System.out.println("The socket is using port " + ds.getLocalPort( ));
}
catch (SocketException ex) {
ex.printStackTrace( );
}

13.3.2.5 public InetAddress getLocalAddress( )


A DatagramSocket's
getLocalAddress(
)
method returns an
InetAddress object that represents the local
address to which the socket is bound. It's rarely
needed in practice. Normally, you either know or
don't care which address a socket is listening to.

13.3.2.6 public SocketAddress getLocalSocketAddress( ) // Java 1.4


The getLocalSocketAddress() method returns a
SocketAddress object that wraps the local
interface and port to which the socket is bound. Like
getLocalAddress( ), it's a little
hard to imagine a realistic use case here. This method probably
exists mostly for parallelism with setLocalSocketAddress().


13.3.3 Managing Connections


Unlike TCP sockets, datagram sockets
aren't very picky about whom
they'll talk to. In fact, by default
they'll talk to anyone, but this is often not what
you want. For instance, applets are only allowed to send datagrams to
and receive datagrams from the applet host. An NFS or FSP client
should accept packets only from the server it's
talking to. A networked game should listen to datagrams only from the
people playing the game. In Java 1.1, programs must manually check
the source addresses and ports of the hosts sending them data to make
sure they're who they should be. However, Java 1.2
adds four methods that let you choose which host you can send
datagrams to and receive datagrams from, while rejecting all
others' packets.

13.3.3.1 public void connect(InetAddress host, int port) // Java 1.2


The connect( ) method doesn't really
establish a connection in the TCP sense. However, it does specify
that the DatagramSocket will send packets to and
receive packets from only the specified remote host on the specified
remote port. Attempts to send packets to a different host or port
will throw an IllegalArgumentException. Packets
received from a different host or a different port will be discarded
without an exception or other notification.

A security check is made when the connect( )
method is invoked. If the VM is allowed to send data to that host and
port, the check passes silently. Otherwise, a
SecurityException is thrown. However, once the
connection has been made, send( ) and
receive( ) on that
DatagramSocket no longer make the security checks
they'd normally make.

13.3.3.2 public void disconnect( ) // Java 1.2


The disconnect( ) method breaks the
"connection" of a connected
DatagramSocket so that it can once again send
packets to and receive packets from any host and port.

13.3.3.3 public int getPort( ) // Java 1.2


If and only if a DatagramSocket is connected, the
getPort( ) method returns the remote port to which
it is connected. Otherwise, it returns -1.

13.3.3.4 public InetAddress getInetAddress( ) // Java 1.2


If and only if a DatagramSocket is connected, the
getInetAddress(
)
method returns the address of the
remote host to which it is connected. Otherwise, it returns null.

13.3.3.5 public InetAddress getRemoteSocketAddress( ) // Java 1.4


If a DatagramSocket is connected, the
getRemoteSocketAddress(
)
method returns the address of the
remote host to which it is connected. Otherwise, it returns null.


13.3.4 Socket Options


The
only socket option supported for datagram sockets in Java 1.1 is
SO_TIMEOUT. Java 1.2 adds SO_SNDBUF and SO_RCVBUF. Java 1.4 adds
SO_REUSEADDR and SO_BROADCAST and enables the specification of the
traffic class.

13.3.4.1 SO_TIMEOUT


SO_TIMEOUT is the amount of time, in
milliseconds, that receive( ) waits for an
incoming datagram before throwing an
InterruptedIOException (a subclass of
IOException). Its value must be nonnegative. If
SO_TIMEOUT is 0, receive( ) never times out. This
value can be changed with the setSoTimeout( )
method and inspected with the getSoTimeout( )
method:

public synchronized void setSoTimeout(int timeout) 
throws SocketException
public synchronized int getSoTimeout( ) throws IOException

The default is to never time out, and indeed there are few situations
in which you would need to set SO_TIMEOUT. You might need it if you
were implementing a secure protocol that required responses to occur
within a fixed amount of time. You might also decide that the host
you're communicating with is dead (unreachable or
not responding) if you don't receive a response
within a certain amount of time.

The setSoTimeout( ) method sets the SO_TIMEOUT
field for a datagram socket. When the timeout expires, an
InterruptedIOException is thrown. (In Java 1.4 and
later, SocketTimeoutException, a subclass of
InterruptedIOException, is thrown instead.) Set
this option before you call receive(
)
. You cannot change it while receive( )
is waiting for a datagram. The timeout argument
must be greater than or equal to zero; if it is not,
setSoTimeout( ) throws a
SocketException. For example:

try {
buffer = new byte[2056];
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
DatagramSocket ds = new DatagramSocket(2048);
ds.setSoTimeout(30000); // block for no more than 30 seconds
try {
ds.receive(dp);
// process the packet...
}
catch (InterruptedIOException ex) {
ss.close( );
System.err.println("No connection within 30 seconds");
}
catch (SocketException ex) {
System.err.println(ex);
}
catch (IOException ex) {
System.err.println("Unexpected IOException: " + ex);
}

The getSoTimeout( ) method returns the current
value of this DatagramSocket
object's SO_TIMEOUT field. For example:

public void printSoTimeout(DatagramSocket ds) {
int timeout = ds.getSoTimeOut( );
if (timeout > 0) {
System.out.println(ds + " will time out after "
+ timeout + "milliseconds.");
}
else if (timeout == 0) {
System.out.println(ds + " will never time out.");
}
else {
System.out.println("Something is seriously wrong with " + ds);
}
}

13.3.4.2 SO_RCVBUF


The SO_RCVBUF option of
DatagramSocket is closely related to the SO_RCVBUF
option of Socket. It determines the size of the
buffer used for network I/O. Larger buffers tend to improve
performance for reasonably fast (say, Ethernet-speed) connections
because they can store more incoming datagrams before overflowing.
Sufficiently large receive buffers are even more important for UDP
than for TCP, since a UDP datagram that arrives when the buffer is
full will be lost, whereas a TCP datagram that arrives at a full
buffer will eventually be retransmitted. Furthermore, SO_RCVBUF sets
the maximum size of datagram packets that can be received by the
application. Packets that won't fit in the receive
buffer are silently discarded.

DatagramSocket has methods to get and set the
suggested receive buffer size used for network input:

public void setReceiveBufferSize(int size) throws SocketException // Java 1.2
public int getReceiveBufferSize( ) throws SocketException // Java 1.2

The setReceiveBufferSize( ) method suggests a
number of bytes to use for buffering input from this socket. However,
the underlying implementation is free to ignore this suggestion. For
instance, many 4.3 BSD-derived systems have a maximum receive buffer
size of about 52K and won't let you set a limit
higher than this. My Linux box was limited to 64K. Other systems
raise this to about 240K. The details are highly platform-dependent.
Consequently, you may wish to check the actual size of the receive
buffer with getReceiveBufferSize( ) after setting
it. The getReceiveBufferSize( ) method returns the
number of bytes in the buffer used for input from this socket.

Both methods throw a SocketException if the
underlying socket implementation does not recognize the SO_RCVBUF
option. This might happen on a non-POSIX operating system. The
setReceiveBufferSize( ) method throws an
IllegalArgumentException if its argument is less
than or equal to zero.

13.3.4.3 SO_SNDBUF


DatagramSocket has methods to get and
set the suggested send buffer size used for network output:

public void setSendBufferSize(int size)  throws SocketException // Java 1.2
public int getSendBufferSize( ) throws SocketException // Java 1.2

The setSendBufferSize( ) method suggests a number
of bytes to use for buffering output on this socket. Once again,
however, the operating system is free to ignore this suggestion.
Consequently, you'll want to check the result of
setSendBufferSize( ) by immediately following it
with a call to getSend BufferSize(
)
to find out the real the buffer size.

Both methods throw a SocketException if the
underlying native network software doesn't
understand the SO_SNDBUF option. The
setSendBufferSize( ) method also throws an
IllegalArgumentException if its argument is less
than or equal to zero.

13.3.4.4 SO_REUSEADDR


The SO_REUSEADDR option does not mean the
same thing for UDP sockets as it does for TCP sockets. For UDP,
SO_REUSEADDR can control whether multiple datagram sockets can bind
to the same port and address at the same time.
If multiple sockets are bound to the same port, received packets will
be copied to all bound sockets. This option is controlled by these
two methods:

public void setReuseAddress(boolean on) throws SocketException  // Java 1.4
public boolean getReuseAddress( ) throws SocketException // Java 1.4

For this to work reliably, setReuseAddress( ) must
be called before the new socket binds to the
port. This means the socket must be created in an unconnected state
using the protected constructor that takes a
DatagramImpl as an argument. In other words, it
won't work with a plain vanilla
DatagramSocket. Reusable ports are most commonly
used for multicast sockets, which will be discussed in the next
chapter. Datagram channels also create unconnected datagram sockets
that can be configured to reuse ports, as you'll see
later in this chapter.

13.3.4.5 SO_BROADCAST


The SO_BROADCAST option controls whether a
socket is allowed to send packets to and receive packets from
broadcast addresses such as 192.168.254.255, the local network
broadcast address for the network with the local address
192.168.254.*. UDP broadcasting is often used for protocols like the
JXTA Peer Discovery Protocol and the Service Location Protocol that
need to communicate with servers on the local net whose addresses are
not known in advance. This option is controlled with these two
methods:

public void setBroadcast(boolean on) throws SocketException  // Java 1.4
public boolean getBroadcast( ) throws SocketException // Java 1.4

Routers and gateways do not normally forward broadcast messages, but
they can still kick up a lot of traffic on the local network. This
option is turned on by default, but if you like you can disable it
thusly:

socket.setBroadcast(false);

This option can be changed after the socket has been bound.


On some implementations, sockets bound to a specific address do not
receive broadcast packets. In other words, use the
DatagramPacket(int port)
constructor, not the DatagramPacket(InetAddress
address, int
port) constructor to listen to broadcasts. This is
necessary in addition to setting the SO_BROADCAST option to true.

13.3.4.6 Traffic class


Traffic class is essentially the same
for UDP as it is for TCP. After all, packets are actually routed and
prioritized according to IP, which both TCP and UDP sit on top of.
There's really no difference between
the setTrafficClass( )
and getTrafficClass( ) methods in
DatagramSocket and those in
Socket. They just have to be repeated here because
DatagramSocket and Socket
don't have a common superclass. These two methods
let you inspect and set the class of service for a socket using these
two methods:


public int getTrafficClass( ) throws SocketException // Java 1.4
public void setTrafficClass(int trafficClass) throws SocketException
// Java 1.4

The traffic class is given as an int between 0 and 255. (Values
outside this range cause
IllegalArgumentExceptions.) This int is a
combination of bit-flags. Specifically:

0x02: Low cost

0x04: High reliability

0x08: Maximum throughput

0x10: Minimum delay


Java always sets the lowest order, ones bit to zero, even if you try
to set it to one. The three high-order bits are not yet used. For
example, this code fragment requests a low cost connection:

DatagramSocket s = new DatagramSocket ( );
s.setTrafficClass(0x02);

This code fragment requests a connection with maximum throughput and
minimum delay:

DatagramSocket s = new DatagramSocket ( );
s.setTrafficClass(0x08 | 0x10);

The underlying socket implementation is not required to respect any
of these requests. They hint at the policy that is desired. Probably
most current implementations will ignore these values completely. If
the local network stack is unable to provide the requested class of
service, it may throw a SocketException, but
it's not required to and truth be told, it probably
won't.


/ 164