UDP packet separation - java

I'm creating an UDP service on andorid.
For clarity part of the code copied here:
byte[] message = new byte[1500];
DatagramPacket packet = new DatagramPacket(message, message.length);
socket = new DatagramSocket(Constants.LISTENING_PORT_NUMBER);
socket.receive(packet);
Problem is that I'm receiving UDP packets continuously.
For example packet #1 (250 byte long), packet #2 (182 byte long), packet #3 (403 byte long) etc...
I need to get and process the separate UDP packets which has variable length.
According to UDP protocol specification UDP packets has message boundaries defined.
However I found no solution in Java which can separate UDP packets.
In my current solution I have to define the packet length which I must read, but I don't know the packet length before I receive it.
Am I missing a point?
EDIT:
Thanks for both Tobias and shazin both are correct answers. Sad I cant's mark two answer as correct.
The socket.receive(packet); will receive until the UDP packet boundary, subsequent packages can be read with another socket.receive(packet);.
My problem should be that during the process of the first message the arrived further messages are not processed because of synchronous processing, now I'll pass the message processing to an async task and hopefully will be able to catch all arrived packets in time.

You cannot know the packet length before hand. You can define a maximum boundary bytes array based on the data you may be receiving. 2048 byte array is recommended.
byte[] message = new byte[2048];
Even if you have variable length in incoming message packets, you can use the following code to receive
byte[] message = new byte[2048];
DatagramPacket packet = new DatagramPacket(message, message.length);
socket = new DatagramSocket(Constants.LISTENING_PORT_NUMBER);
socket.receive(packet);
String data = new String(packet.getData(), 0, packet.getLength());
getData and getLength methods can be used to determine the size of the received packet.

Maybe I'm missing something here, but a DatagramPacket is one packet that is sent. It has the getLength() and getOffset() methods require to get to the data. I believe that there is also a getData() that returns the data sent.
Here you have a link That can help you further.

Related

UDP response packet contents getting cut short

I'm trying to create a simple Java UDP Client-Server program. The server/host waits for an appropriate request from the client before doing something. Everything seems to be working fine but the reply from the host to the client is always truncated for some reason.
I assume it has something to do with the the length of "Bob" as all responses from the host is shortened to 3. I tried messing around with setLength() and the buffer size but can't seem to figure it out...
Client.java:
public class Client {
public static void main(String[] args) throws Exception {
//Use Java's built-in DatagramSocket and DatagramPacket to implement UDP
DatagramSocket socket = new DatagramSocket(); //Create socket object to send data
socket.setSoTimeout(5000); //Throw an exception if no data received within 5000ms
//Create scanner to grab user input
Scanner input = new Scanner(System.in);
System.out.print("Please enter a message to send to Alice: ");
String bobInput = input.nextLine(); //Storing user input
input.close(); //Close scanner to prevent memory leaks
byte[] buffer = new byte[65535];
//Create packet containing message
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("localhost"), 1500);
packet.setData(bobInput.getBytes());
socket.send(packet); //Send message to host
socket.receive(packet);
System.out.println("Received from Alice: " + new String(packet.getData(),0,packet.getLength()));
socket.close();
}
}
Host.java
public class Host {
public static void main(String[] args) throws Exception {
//Use Java's built-in DatagramSocket and DatagramPacket to implement UDP
DatagramSocket socket = new DatagramSocket(1500); //Create a socket to listen at port 1500
byte[] buf = new byte[65535]; //Byte array to wrap
System.out.println("Parameters successfully read. Listening on port 1500...");
//While-loop to keep host running until terminated
while (true) {
DatagramPacket packet = new DatagramPacket(buf, buf.length); //Create a packet to receive message
socket.receive(packet); //Receive the packet
//If Alice receives a packet with the message "Bob"
if(new String(packet.getData(),0,packet.getLength()).equals("Bob")) {
System.out.println("Bob has sent a connection request.");
String test = "Hello Bob!";
packet.setData(test.getBytes());
System.out.println("Text sent: " + new String(packet.getData(),0,packet.getLength()));
}
}
}
}
Console output for client:
Please enter a message to send to Alice: Bob
Received from Alice: Hel
Console output for host:
Parameters successfully read. Listening on port 1500...
Bob has sent a connection request.
Text sent: Hello Bob!
It's my first time working with UDP so I apologize if its some basic mistake that I made.
In the client, you create a packet of length 3 (because the content is 'Bob'). You use the same packet for a receive, which per the doc will then truncate the received data to the packet length.
The DatagramPacket class does not appear to distinguish 'length of underlying buffer' from 'length of data in buffer'.
Best to use separate packet structures; the send packet just needs to contain 'Bob'; the receive packet needs to be large enough for the maximum expected response.
(Debugging hint: figuring this out starts with noticing that it's unlikely to be mere coincidence that the lengths of the transmitted message and of the truncated received message are identical).
Typically, in cases like this, you should create a custom protocol, either textual or binary, in which you specifies the length of the message to be read; it is not a TCP, so you can only wait until the entire datagram has been sent or received and after that parse the contents and extract the message.
This requires defining your own protocol to be used on top of UDP; there are two macro types of protocols: text-type and binary-type.
In text-type protocols you often make use of integers to put as prefixes that indicate the actual length of the message to be read. In fact if you know that the length of your messages, for example, stands at 32bit you can read the first four bytes of the datagram and know how many more you will have to read to get your string. The more complex text protocols make use of delimiting characters to specify a format that defines options and data; of this family you will certainly be familiar with HTTP.
In binary-type protocols it is a little more complex, you can have flags, various lengths referring to different fields that may or may not be optional.
In short in this case you have to define for yourself a frame type to use and interpret. If you have to deal with fragmentation, options and variable lengths, I would recommend that you take a look at this type of format.
Keep also in mind that with UDP you should in real projects also handle the retransmission of lost packets.
Anyway, it's probably a typo, but your code is definitely missing a send() that actually sends the response data.
So from your code we can't see what you actually send.
In conclusion, to answer you, from what can be inferred from the part of the code given and the output provided, you make use of setData() to send "Bob." The documentation for that method is as follows:
Set the data buffer for this packet. With the offset of this
DatagramPacket set to 0, and the length set to the length of buf.
So, no matter what buffer you initialized the datagram with it will now be reduced to a maximum length of three. In fact, when you receive the response you read the message with getLength() which will always return three.

Java UDP DatagramSocket stops receiving

I have a DatagramSocket where I'm receiving in a loop and it eventually just stops receiving packets. I send the server a hello message that establishes the connection. Then I start reciving packets as expected. Eventually it just stops receiving.
The sending server has verified that they are still sending packets to the same address via tcp dump but eventually this code hangs on the receive call.
Is there anything that would cause the socket to stop receiving?
String hello = "hello";
InetAddress IPAddress = InetAddress.getByName("serveraddress");
DatagramPacket outboundPacket = new DatagramPacket(hello.getBytes(),hello.getBytes().length, IPAddress, 54321 );
DatagramSocket registerSocket = new DatagramSocket(61646);
registerSocket.send(outboundPacket);
int count = 0;
while(!done){
count++;
byte[] inboundData = new byte[1368];
DatagramPacket inboundPacket = new DatagramPacket(inboundData,inboundData.length);
System.out.println(registerSocket.getPort());
System.out.println(registerSocket.getLocalPort());
//Eventually locks up here after hundreds of successful receives
registerSocket.receive(inboundPacket);
byte[] data = inboundPacket.getData();
String test = new String(data, "ISO-8859-1");
System.out.println(test+"---"+count);
}
registerSocket.close();
If you're behind NAT, the mapping will time out if there's no outbound traffic for too long. Make sure to send an outbound datagram every few minutes to keep the mapping active in the router.
Not clear from the question, whether you work with several DatagramSockets inside one process: This would be non-trivial. See Java: Receiving an UDP datagram packet with multiple DatagramSockets
Unless using multicast, a newly created datagram socket will inherit the process' receiving cursor and clamp
the existing one from receiving.

Can a received DatagramPacket be used to be sent again?

I am testing a UDP echo server, is the following code correct?
DatagramSocket s = ...
DatagramPacket p = new DatagramPacket(new byte[512], 512);
...
s.recieve(p);
s.send(p);
My question is, can I send the DatagramPacket just as I recieved it? According to the java specification, the contructor I used constructs a DatagramPacket 'for recieving use'. I am not sure if that state changes when the packet has been modified through s.recieve, or if that 'for recieve use state' is permanent.
If the code is correct, is there any reason why in the tutorial they construct a whole new DatagramPacket? (maybe just clarity?)
https://docs.oracle.com/javase/tutorial/networking/datagrams/clientServer.html
Yes, and it's quite common. If you receive a request, the DatagramPacket already has the return address in it, so all you need to do is put the response data into it and send it back.

Do UDP packets arrive in entirety?

I know that TCP simulates a stream, so typically reads will start as soon as any data is received. Thats why I use this snippet to make sure it waits for the entire packet before acting on it
int packetSize = inputStream.readShort() ;
byte packetBuffer[] = new byte[packetSize];
int byteTrans = 0;
while ( byteTrans < packetSize )
{
inputStream.read( packetBuffer , byteTrans , 1 );
byteTrans++;
}//
For UDP however, will I still have to work around the same problem? I don't think so because TCP basically simulates a stream by breaking up your data into smaller packets and sending it, while in UDP you have more control over the whole process.
For reading UDP I use
byte[] packetByte = new byte[packetSize];
DatagramPacket packet = new DatagramPacket(packetByte, packetByte.length);
socket.receive(packet);
Do I have to implement a similar system for UDP?
When you send a datagram packet, it will be received in its entirety, yes (when it is actually received - continue reading the answer).
The behavior of UDP and TCP varies in much more than just that. UDP does not guarantee packets will be received in the same order they are sent (or even received at all) or that they are recevied exactly once. UDP is more of a "fire and forget", whereas TCP maintains a connection state.
In short, if the packet is received, you will get the whole packet. But it may not be received at all.

Video file packets over UDP -- incremental read and stream

I would like to transfer a video file read from disk to a receiver using UDP DatagramPacket in Java.
The key points are as follows: though the file to be transmitted is read from disk, I should assume that I'm not aware of the file size. The total file need to be read incrementally and the datagram packets of the file should be of varying sizes.
In short, I should assume that I'm streaming a live video to a receiver without knowing how much data I would totally need to send and at what rate the data will get generated.
Right now, I have a code which reads the file on the disk at once and convert into datagram packets to transmit using UDP socket. But I have no clue on how could I packetize the file without knowing the original file size and read incrementally that would mock the live streaming of a video.
Any inputs on to get this idea implemented using Java would be very useful. I need to implement a real time file transfer protocol once I get this basic thing working.
Sender:
File file = new File("/crazy.mp4");
FileInputStream fis = new FileInputStream(file);
DatagramPacket pack;
int size = 0;
byte[] buffer = new byte[((int) file.length())];
ByteBuffer bb = ByteBuffer.allocate(4);
bb.order(ByteOrder.BIG_ENDIAN);
while (true) {
size = fis.read(buffer);
pack = new DatagramPacket(buffer, buffer.length, address,
packet.getPort());
socket.send(pack);
}
Receiver:
File file = new File("/crazyRecv.mp4");
FileOutputStream fos = new FileOutputStream(file);
DatagramPacket rpacket = new DatagramPacket(buffer, buffer.length);
while (true) {
socket.receive(rpacket);
fos.write(rpacket.getData(), 0, rpacket.getLength());
}
Thanks.
This code of sending and receiving UDP packets can not guarantee to successfully recreate the file in client side.
UDP is Unreliable - There is no low level acknowledgement and packet retransmission mechanism like in TCP so you have to implement this. Packets may be lost and never received at client side
UDP is not sequential - You can not just expect the UDP packets to recieve at client end sequentially. First packet may arrive last and last packet first, subsequently corrupting the file. TCP guarantees sequential delivery.
You have to write your own Application Level protocol, if you still want to use. For Example
You send a packet with content "File Start"
The client sends an ack packet for that "File Start : Received"
If you didn't receive "File Start : Received" then you have to go to step 1
And then send packets with an Unique id "Packet 1 " + packet data
The client sends an ack packet for that "Packet 1 : Received"
If you didn't receive "Packet 1 : Received" then you have to go to step 4
Do step 4 - 6 for all packets
You send a packet with content "File End"
The client sends an ack packet for that "File End: Received"
If you didn't receive "File End : Received" then you have to go to step 8

Categories