DatagramPacket not transmitting the right message - java

I'm implementing a client/server application using UDP transmissions. Here is my part of my code :
Client :
InetAddress serverAddress = ...
int serverPort = ...
DatagramSocket socket = new DatagramSocket(9999);
...
String message = "<HELLO>";
byte[] outbuffer = new byte[1000];
outbuffer = message.getBytes();
DatagramPacket packet = new DatagramPacket(outbuffer, outbuffer.length, serverAddress, serverPort);
socket.send(this.packet);
Server :
DatagramSocket serverSocket = new DatagramSocket(9876);
...
byte[] inbuffer = new byte[1000];
DatagramPacket packet = new DatagramPacket(inbuffer, inbuffer.length);
serverSocket.receive(packet);
String response = new String(packet.getData(), 0, packet.getLength());
System.out.println(response);
if("<HELLO>".equals(response)){
System.out.println("OK");
} else {
System.out.println("ERROR");
}
My problem is the following: if I print the response String on the client side that is comming from the client, everything looks fine ("").
But for some reasons when I trie to compare the response coming from the server using .equals or a RegExp it fails !
May be it's related to String encoding but I don't know where and why it fails. Both client and server are running on the same host right now, so it might not be related to JVM differences.

You're currently using the platform default encoding to both encode and decode strings. You should absolutely not do that. Specify the encoding both in the getBytes() call and the constructor call, e.g.
byte[] outBuffer = message.getBytes("UTF-8");
Also note that your current code creates a byte array of length 1000 and then immediately throws it away:
byte[] outbuffer = new byte[1000];
// Byte array created on previous line is now useless!
outbuffer = message.getBytes();
... don't do that.
We can't really tell much more from the code you've given us - if you could produce short but complete programs demonstrating the problem, that would really help.
For debugging, I would suggest you log the contents of the datagram packet you receive, while still in binary. Presumably it's not what you expected, but that doesn't help to show what it was.
EDIT: Here's a pair of short but complete programs which do work:
import java.net.*;
public class Server {
public static void main(String[] args) throws Exception{
DatagramSocket socket = new DatagramSocket(9999);
byte[] inbuffer = new byte[1000];
DatagramPacket packet = new DatagramPacket(inbuffer, inbuffer.length);
socket.receive(packet);
String response = new String(packet.getData(), 0,
packet.getLength(), "UTF-8");
System.out.println(response);
if("<HELLO>".equals(response)){
System.out.println("OK");
} else {
System.out.println("ERROR");
}
}
}
// Client.java
import java.net.*;
public class Client {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket();
byte[] output = "<HELLO>".getBytes("UTF-8");
DatagramPacket packet = new DatagramPacket(output, output.length,
InetAddress.getLocalHost(),
9999);
socket.send(packet);
}
}

You have a variable response and reponse.
I am assuming that they won't be the same and your test should fail.
This is the sort of thing you should be able to see in a debugger.

Related

May UDP group the sending of datagrams?

With UDP, if I send two DatagramPackets on one DatagramSocket (let's say first datagram say "ABCD" and the second say "EFGH"),
is it theorically possible that my first call to "receive" on the socket give me a DatagramPacket containing "ABCDEFGH"?
In other words, does messages sent with UDP can be grouped into one message and if so, does UDP "remembers" it was several distincts messages in the first place?
Let's assume my client is :
//DSender.java
import java.net.*;
public class DSender{
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
InetAddress ip = InetAddress.getByName("127.0.0.1");
// Send a first message
String str = "ABCD";
DatagramPacket dp1 = new DatagramPacket(str.getBytes(), str.length(), ip, 3000);
ds.send(dp1);
// Send a second message (on the same socket)
str = "EFGH";
DatagramPacket dp2 = new DatagramPacket(str.getBytes(), str.length(), ip, 3000);
ds.send(dp2);
ds.close();
}
}
And my server is:
//DReceiver.java
import java.net.*;
public class DReceiver{
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket(3000);
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, 1024);
ds.receive(dp);
String str = new String(dp.getData(), 0, dp.getLength());
System.out.println(str);
ds.close();
}
}
This code may output "ABCD", it may also output "EFGH" (if first message is lost), it may also output nothing at all (if both messages are lost), but can it output "ABCDEFH"?
No. UDP datagrams are received intact and entire, or not at all. Also possibly multiple times, out of order, ... but never coalesced.

Serialization and Deserialization - Socket Programming

I am working on a client server java application, using serialization and deserialization. At first I simply want to send a serialized packet to the server that deserialize it and print it on the screen.
Here is mi Client:
public class Client {
public static void main(String[] args) throws IOException {
int portUDP = Integer.parseInt("6004");
InetAddress host = InetAddress.getByName("127.0.0.1");
DatagramSocket UDPsock = new DatagramSocket();
ByteArrayOutputStream oSt = new ByteArrayOutputStream();
ObjectOutputStream ooSt = new ObjectOutputStream(oSt);
packet pck = new packet(2,1,3,"try");
ooSt.writeObject(pck);
ooSt.flush();
byte[] sendBuf = new byte[30];
sendBuf = oSt.toByteArray();
DatagramPacket payload = new DatagramPacket(sendBuf, sendBuf.length, host, portUDP);
UDPsock.send(payload);
UDPsock.close();
}
}
And here is my Server:
public class Server {
public static void main(String[] args) throws IOException, ClassNotFoundException {
int portUDP = 6004;
DatagramSocket UDPsock = new DatagramSocket(portUDP);
byte[] payload = new byte[30];
DatagramPacket inUDP = new DatagramPacket(payload, payload.length);
UDPsock.receive(inUDP);
ByteArrayInputStream oSt = new ByteArrayInputStream(inUDP.getData());
ObjectInputStream ooSt = new ObjectInputStream(oSt);
packet pck = (packet)ooSt.readObject();
pck.printContents();
UDPsock.close();
}
}
I think that my problem is in the deserialization but I am not able to spot it. Please help me
This are my errors:
Exception in thread "main" java.io.EOFException
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2353)
at java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3092)
at java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:2892)
at java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1075)
at java.io.ObjectStreamClass.readNonProxy(ObjectStreamClass.java:717)
at java.io.ObjectInputStream.readClassDescriptor(ObjectInputStream.java:833)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1609)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at Server.main(Server.java:23)
byte[] payload = new byte[30];
The problem is here. Serialized streams are far bigger than this. Try 576.
And keep a watch on the size of the outgoing byte array as well. If this gets over 576 you will run into IP fragmentation, which will start to cause datagram loss, and you will eventually run into the path MTU which is generally only 1250-1500 bytes. So you can't serialize large objects.
Also:
ByteArrayInputStream oSt = new ByteArrayInputStream(inUDP.getData());
should be:
ByteArrayInputStream oSt = new ByteArrayInputStream(inUDP.getData(), inUDP.getOffset(), inUDP.getLength());

Java sending/receiving UDP packet missing data inside

I am implementing a p2p application, in which nodes communicate by UDP packet. The packets read from InputStream are sometime not complete.
Here is my code:
...
protected String key;
protected Identifier messId; //Identifier hold a BigInteger
protected String range;
protected String concat;
....
public ReplicationMessage(DataInput in) throws IOException {
fromStream(in);
}
public void fromStream(DataInput in)
try {
super.fromStream(in);
int length=in.readInt();
byte[] data=new byte[length];
in.readFully(data);
concat = new String(data);
System.out.println("concat: "+concat);
messId = new Identifier(in);
} catch (IOException e) {
e.printStackTrace();
}
}
public void toStream(DataOutput out) {
try {
super.toStream(out);
byte[] data = concat.getBytes();
out.writeInt(data.length);
out.write(data);
messId.toStream(out);
} catch (IOException e) {
e.printStackTrace();
}
}
the read packet sometime is complete, for example
concat: 179136678282544:140737488355328
but sometime is not complete, for example
concat: 179136678282544
concat: 179136678282544
concat: 179136678282544
Can any one tell me what the problem is?
Many thanks
Here are the code for sending/receiving the UDP packet
for sending:
private void sendMessage(int comm, Message message, InetAddress ip, int port)
throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
dout.writeInt(comm);
dout.writeByte(message.code());
message.toStream(dout);
dout.close();
byte[] data = bout.toByteArray();
if (data.length > DATAGRAM_BUFFER_SIZE) {
throw new IOException("Message too big, size="+data.length+
" bytes, max="+DATAGRAM_BUFFER_SIZE+" bytes");
}
DatagramPacket packet = new DatagramPacket(data, data.length, ip, port);
socket.send(packet);
}
For receiving the UDP packet
byte[] buffer = new byte[DATAGRAM_BUFFER_SIZE];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
The sending node and receiving node belonging to one machine. the Buffer receiving packet is set to 10*1024 bytes which is much larger than packet length
Here is code for turning incoming datapacket into stream
ByteArrayInputStream bin = new ByteArrayInputStream(packet.getData(),
packet.getOffset(), packet.getLength());
DataInputStream din = new DataInputStream(bin);
int comm = din.readInt();
byte messCode = din.readByte();
Message message = factory.createMessage(messCode, din);
UDP does not deliver damaged or partial packets. Either you aren't sending all the data or you aren't unpacking it properly. You still haven't posted all the code concerned so it is not possible to say exactly where.

int array sent and receive in datagram socket programming in java

I try to send a integer array via datagram socket. What is the best way to accomplish this.
MY sending code is:
public void sendObj(Object obj) {
try{
byteArr = new ByteArrayOutputStream();
objOut = new ObjectOutputStream(byteArr);
objOut.writeObject(obj);
byte[] b = byteArr.toByteArray();
DatagramPacket dgram = new DatagramPacket(b, b.length, InetAddress.getByName("230.0.0.1"), 4446); // multicast
socket.send(dgram);
System.out.println("Package is sent!");
}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
}
And receiving code is:
byte[] b = new byte[65535];
ByteArrayInputStream b_in = new ByteArrayInputStream(b);
DatagramPacket dgram = new DatagramPacket(b, b.length);
socket.receive(dgram); // blocks
ObjectInputStream o_in = new ObjectInputStream(b_in);
Object o = o_in.readObject();
dgram.setLength(b.length); // must reset length field!
b_in.reset(); //
However when I receive it gives StreamException for unknown header value 00000
We solved that problem by a basic changes. We used a string like "100200300..." to symbolize the array by separating element with two 0' so in that way we did not use ArrayList.
You have to use getbyte() method to get the bytes and the put these bytes into a datagram packet instance and then pass it to the client or send it...
Use
arrayName.getBytes(); /// save this into some byte[] temp = new byte[size];
and make a datagram packet and put its argumnets and send it

Send and receive serialize object on UDP

I am trying to send a serialized object from a server process to a client process in Java using UDP. The problem is that the client is being blocked on the receive method. Can someone help?!
here is the server code for sending the object:
ClientModel C1= new ClientModel(100,"Noor","Noor",38,38,"asd");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(C1);
oos.flush();
byte[] Buf= baos.toByteArray();
packet = new DatagramPacket(Buf, Buf.length, client, port);
socket.send(packet);
and here is the client code for receiving the object:
byte[] buffer = new byte[100000];
packet = new DatagramPacket(buffer, buffer.length );
socket.receive(packet);
System.out.println("packet received");
I just want to receive the object to be able to reconstruct but I cannot receive the packet itself.
I dont know what you want to accomplish in the end, but working with UDP is not so easy... the main reason is in the Description of the DatagramPacket Object:
Datagram packets are used to implement
a connectionless packet delivery
service. Each message is routed from
one machine to another based solely
on information contained within that
packet. Multiple packets sent from
one machine to another might be routed
differently, and might arrive in any
order. Packet delivery is not
guaranteed.
A good tutorial when working with udp is http://download.oracle.com/javase/tutorial/networking/datagrams/clientServer.html
About your blocking:
Receives a datagram packet from this
socket. When this method returns, the
DatagramPacket's buffer is filled with
the data received. The datagram packet
also contains the sender's IP address,
and the port number on the sender's
machine.
This method blocks until a datagram is
received. The length field of the
datagram packet object contains the
length of the received message. If the
message is longer than the packet's
length, the message is truncated.
I didnt really test it, but I am pretty sure - based on the description - that the datagramsocket.reseive function will block until the packet is filled (in your case until 100000 bytes are received).
I would suggest you start with a datagrampacket with a fixed known length, where you transmit the size of the actual payload. Something like:
public static void main(String[] args) {
ClientModel c1 = new ClientModel ();
c1.data = 123;
c1.name = "test";
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(c1);
oos.flush();
// get the byte array of the object
byte[] Buf= baos.toByteArray();
int number = Buf.length;;
byte[] data = new byte[4];
// int -> byte[]
for (int i = 0; i < 4; ++i) {
int shift = i << 3; // i * 8
data[3-i] = (byte)((number & (0xff << shift)) >>> shift);
}
DatagramSocket socket = new DatagramSocket(1233);
InetAddress client = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(data, 4, client, 1234);
socket.send(packet);
// now send the payload
packet = new DatagramPacket(Buf, Buf.length, client, 1234);
socket.send(packet);
System.out.println("DONE SENDING");
} catch(Exception e) {
e.printStackTrace();
}
}
On the other side you now KNOW your sizes:
public static void main(String[] args) {
try {
DatagramSocket socket = new DatagramSocket(1234);
byte[] data = new byte[4];
DatagramPacket packet = new DatagramPacket(data, data.length );
socket.receive(packet);
int len = 0;
// byte[] -> int
for (int i = 0; i < 4; ++i) {
len |= (data[3-i] & 0xff) << (i << 3);
}
// now we know the length of the payload
byte[] buffer = new byte[len];
packet = new DatagramPacket(buffer, buffer.length );
socket.receive(packet);
ByteArrayInputStream baos = new ByteArrayInputStream(buffer);
ObjectInputStream oos = new ObjectInputStream(baos);
ClientModel c1 = (ClientModel)oos.readObject();
c1.print();
} catch(Exception e) {
e.printStackTrace();
}
}
The CientModel clas sI used:
public class ClientModel implements Serializable{
private static final long serialVersionUID = -4507489610617393544L;
String name = "";
int data = 1;
void print() {
System.out.println(data +": " + name);
}
}
I tested this code and it works just fine. Hope that helps (I got the byte-To-int and around from http://www.tutorials.de/java/228129-konvertierung-von-integer-byte-array.html)
Edit: As stated in the comments, it is often a very bad idea to use UDP, mainly, because you do not know if your packets are received in the correct order, or even at all. UDP does NOT guarantee that. I didn't do too much udp programming, but the only part you can rely on (if I understood correctly) is, that if you get a packet and it fits within the datagram (65,527 bytes - see https://en.wikipedia.org/wiki/User_Datagram_Protocol) it will contain the whole thing. So if you do not care about the order in which the message come and your object fits in the datagram, you should be fine.
Edit2: As for the code: do not use it as is. it is only an example, ind UDP you should only have one type of packet, and this with a known size. that way you do not need to send the "size". If you use the code as shown above, and one packet is dropped, the next packet will be the wrong size (i.e. the first packet is dropped, suddenly you are checking the first bytes of the payload to get the size).
I didnt really test it, but I am pretty sure - based on the
description - that the datagramsocket.reseive function will block
until the packet is filled (in your case until 100000 bytes are
received).
This is wrong. The receive function will block until a datagram is received, which can be smaller than the buffer size (and usually will be). The method packet.getLength() will tell you how big it was.

Categories