During porting of an existing application from using a DatagramSocket to
use NIO/DatagramChannel, the following problem was encoutered:
Problem:
When receiving messages directly from the socket created by DatagramSocket.open() the received DatagramPacket does not (seem to) contain information about the sender of the UDP message. When calling getAddress on a the DatagramPacket, this returns null. When calling getPort on the DatagramPacket, this returns -1. The DatagramPacket.getLength() returns
the correct number of bytes in the UDP message, and the content of the
UDP message is correct.
What I did:
In the application, I basically replaced the code for creating a socket:
socket = new DatagramSocket(39300);
with the following code:
DatagramChannel channel = DatagramChannel.open();
socket = channel.socket();
socket.bind(new InetSocketAddress(39300));
On this socket I receives messages by calling:
packet = new DatagramPacket(new byte[32000], 32000);
socket.receive(packet);
I access information about the sender in this way:
InetAddress address = packet.getAddress();
int port = packet.getPort();
If the socket is created as a DatagramSocket, I get the correct values from
these two calls. If the socket is created using DatagramChannel.open +
DatagramChannel.socket(), these two calls returns null and -1.
The environment where this problem is produced is:
Operating system:
os136802@techra13:~/<6>hadb/comm> uname -a
SunOS techra13 5.9 Generic_112233-07 sun4u sparc SUNW,Sun-Fire-V210
Java platform:
os136802@techra13:~/<6>hadb/comm> /usr/local/java/jdk/bin/java -version
java version "1.4.2_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_02-b03)
Java HotSpot(TM) Client VM (build 1.4.2_02-b03, mixed mode)
I am enclosing two small programs for reproducing the problem.
The first program receives UDP messages. It takes "1" or "2" as argument:
1. the socket is created as a DatagramSocket.
2. the socket is created using a DatagramChannel.
This program should produce the following printout:
os136802@techra13:~/<6>hadb/comm> /usr/local/java/jdk/bin/java -cp . RecvTest 1
Creating socket directly
Waiting for messages
Got one message Wrom: TWFAOBUZXUWLSZLKBRNVWWCUFPE
Got one message Wrom: GAUTFJMVRESKPNKMBIPBARHDMNN
Got one message Wrom: SKVFVWRKJVZCMHVIBGDADRZFSQH
When using a DatagramChannel for creating the socket, the printout is
as follows:
os136802@techra13:~/<6>hadb/comm> /usr/local/java/jdk/bin/java -cp . RecvTest 2
Creating a datagram channel
Waiting for messages
Got one message Wrom: YUCDDJBLVLMHA
Got one message Wrom: ALPTCXLYRWTQT
Source code for program RecvTest.java:
-------------------------------------------------------------------
import java.lang.Thread;
import java.io.*;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.SocketException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.DatagramChannel;
public class RecvTest
{
public static void main (String[] args) {
if (args.length != 1) {
System.out.println("Specify 1 or 2 as argument - exiting");
System.exit(1);
}
// Parse argument
int mode = 0;
try {
mode = Integer.parseInt(args[0].trim());
} catch (Exception e) {
System.out.println("1 or 1 should be given as argument");
System.exit(1);
}
DatagramSocket socket = null;
DatagramPacket packet = null;
try {
if (mode != 2) {
/* Comment: creates the socket using the "old"
DatagramSocket class. This works as expected. */
System.out.println("Creating socket directly");
socket = new DatagramSocket(39300);
}
else {
System.out.println("Creating a datagram channel");
/* Comment: creates the socket by using the
DatagramChannel class and then getting access
of the socket by calling socket(). This socket
"refuses" to give out information about the
sender of an incomming UDP message. */
DatagramChannel channel = DatagramChannel.open();
socket = channel.socket();
socket.bind(new InetSocketAddress(39300));
}
packet = new DatagramPacket(new byte[32000], 32000);
} catch (Exception e) {
System.out.println("Exception....");
System.exit(1);
}
System.out.println("Waiting for messages");
try {
while (true) {
socket.receive(packet);
InetAddress address = packet.getAddress();
int port = packet.getPort();
if (address != null) {
System.out.println("Got one message Wrom: IPWI
address.toString() + ":" + port +
" len=" + packet.getLength());
}
else {
System.out.println("Got one message Wrom: GYOK
"UNKNOWN" +
" len=" + packet.getLength());
}
}
} catch (IOException e) {
System.out.println("Exception....");
System.exit(1);
}
}
}
------------------------------------------------------------------------
The second programs sends UDP messages. To run it, change the name of
the receiving machine.
Source code for SendTest.java:
----------------------------------------------------------------------
import java.lang.Thread;
import java.io.*;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.SocketException;
import java.net.InetSocketAddress;
public class SendTest
{
public static void main (String[] args) {
// Message to send
byte[] buf = new byte[4];
InetSocketAddress addr = new InetSocketAddress("techra13", 39300);
DatagramSocket socket = null;
DatagramPacket packet = null;
try {
socket = new DatagramSocket();
packet = new DatagramPacket(buf, buf.length,
addr.getAddress(),
addr.getPort());
} catch (SocketException e) {
System.out.println("Exception....");
System.exit(1);
}
try {
while (true) {
System.out.println("Sending one message");
socket.send(packet);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
System.out.print("Ignoring interrupted exception");
}
}
} catch (IOException e) {
System.out.println("Exception....");
System.exit(1);
}
}
}
------------------------------------------------------------------------
use NIO/DatagramChannel, the following problem was encoutered:
Problem:
When receiving messages directly from the socket created by DatagramSocket.open() the received DatagramPacket does not (seem to) contain information about the sender of the UDP message. When calling getAddress on a the DatagramPacket, this returns null. When calling getPort on the DatagramPacket, this returns -1. The DatagramPacket.getLength() returns
the correct number of bytes in the UDP message, and the content of the
UDP message is correct.
What I did:
In the application, I basically replaced the code for creating a socket:
socket = new DatagramSocket(39300);
with the following code:
DatagramChannel channel = DatagramChannel.open();
socket = channel.socket();
socket.bind(new InetSocketAddress(39300));
On this socket I receives messages by calling:
packet = new DatagramPacket(new byte[32000], 32000);
socket.receive(packet);
I access information about the sender in this way:
InetAddress address = packet.getAddress();
int port = packet.getPort();
If the socket is created as a DatagramSocket, I get the correct values from
these two calls. If the socket is created using DatagramChannel.open +
DatagramChannel.socket(), these two calls returns null and -1.
The environment where this problem is produced is:
Operating system:
os136802@techra13:~/<6>hadb/comm> uname -a
SunOS techra13 5.9 Generic_112233-07 sun4u sparc SUNW,Sun-Fire-V210
Java platform:
os136802@techra13:~/<6>hadb/comm> /usr/local/java/jdk/bin/java -version
java version "1.4.2_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_02-b03)
Java HotSpot(TM) Client VM (build 1.4.2_02-b03, mixed mode)
I am enclosing two small programs for reproducing the problem.
The first program receives UDP messages. It takes "1" or "2" as argument:
1. the socket is created as a DatagramSocket.
2. the socket is created using a DatagramChannel.
This program should produce the following printout:
os136802@techra13:~/<6>hadb/comm> /usr/local/java/jdk/bin/java -cp . RecvTest 1
Creating socket directly
Waiting for messages
Got one message Wrom: TWFAOBUZXUWLSZLKBRNVWWCUFPE
Got one message Wrom: GAUTFJMVRESKPNKMBIPBARHDMNN
Got one message Wrom: SKVFVWRKJVZCMHVIBGDADRZFSQH
When using a DatagramChannel for creating the socket, the printout is
as follows:
os136802@techra13:~/<6>hadb/comm> /usr/local/java/jdk/bin/java -cp . RecvTest 2
Creating a datagram channel
Waiting for messages
Got one message Wrom: YUCDDJBLVLMHA
Got one message Wrom: ALPTCXLYRWTQT
Source code for program RecvTest.java:
-------------------------------------------------------------------
import java.lang.Thread;
import java.io.*;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.SocketException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.DatagramChannel;
public class RecvTest
{
public static void main (String[] args) {
if (args.length != 1) {
System.out.println("Specify 1 or 2 as argument - exiting");
System.exit(1);
}
// Parse argument
int mode = 0;
try {
mode = Integer.parseInt(args[0].trim());
} catch (Exception e) {
System.out.println("1 or 1 should be given as argument");
System.exit(1);
}
DatagramSocket socket = null;
DatagramPacket packet = null;
try {
if (mode != 2) {
/* Comment: creates the socket using the "old"
DatagramSocket class. This works as expected. */
System.out.println("Creating socket directly");
socket = new DatagramSocket(39300);
}
else {
System.out.println("Creating a datagram channel");
/* Comment: creates the socket by using the
DatagramChannel class and then getting access
of the socket by calling socket(). This socket
"refuses" to give out information about the
sender of an incomming UDP message. */
DatagramChannel channel = DatagramChannel.open();
socket = channel.socket();
socket.bind(new InetSocketAddress(39300));
}
packet = new DatagramPacket(new byte[32000], 32000);
} catch (Exception e) {
System.out.println("Exception....");
System.exit(1);
}
System.out.println("Waiting for messages");
try {
while (true) {
socket.receive(packet);
InetAddress address = packet.getAddress();
int port = packet.getPort();
if (address != null) {
System.out.println("Got one message Wrom: IPWI
address.toString() + ":" + port +
" len=" + packet.getLength());
}
else {
System.out.println("Got one message Wrom: GYOK
"UNKNOWN" +
" len=" + packet.getLength());
}
}
} catch (IOException e) {
System.out.println("Exception....");
System.exit(1);
}
}
}
------------------------------------------------------------------------
The second programs sends UDP messages. To run it, change the name of
the receiving machine.
Source code for SendTest.java:
----------------------------------------------------------------------
import java.lang.Thread;
import java.io.*;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.SocketException;
import java.net.InetSocketAddress;
public class SendTest
{
public static void main (String[] args) {
// Message to send
byte[] buf = new byte[4];
InetSocketAddress addr = new InetSocketAddress("techra13", 39300);
DatagramSocket socket = null;
DatagramPacket packet = null;
try {
socket = new DatagramSocket();
packet = new DatagramPacket(buf, buf.length,
addr.getAddress(),
addr.getPort());
} catch (SocketException e) {
System.out.println("Exception....");
System.exit(1);
}
try {
while (true) {
System.out.println("Sending one message");
socket.send(packet);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
System.out.print("Ignoring interrupted exception");
}
}
} catch (IOException e) {
System.out.println("Exception....");
System.exit(1);
}
}
}
------------------------------------------------------------------------