Is UDP losing part of my packet here? - java

Im trying to send a packet back to the user informing them of all the people currently on the server, when they send a message to the server which has the word "who" in it.
Here is my code:
else if( response.contains( "who" ) )
{
System.out.println( "Size of names collection: "+names.size() );
buf = null;
buf = names.toString().getBytes();
int thisPort = packet.getPort();
packet = new DatagramPacket( buf, buf.length,packet.getAddress(),thisPort );
socket.send(packet);
}
The output of the print statement above is 2 indicating that there are two people on, for example andrew and james. Now when I package it up and send it I would expect it to output this:
[Andrew, James]
But instead the client gets:
[Andrew,
And thats it. Whats the problem? BTW I have to use UDP for this and can't switch to TCP
UPDATE
Here is the code in the client class that receives the packets:
while( true )
{
try
{
// Set the buf to 256 to receive data back from same address and port
buf = null;
buf = new byte[256];
packet = new DatagramPacket(buf, buf.length, address, 4445);
socket.receive(packet);
String response = new String( packet.getData() );
// Receive the packet back
System.out.println( response );
}
catch( IOException e )
{
}
}

Your datagram is being truncated to 256 byes because that's the size of the buffer you declared for the receiving DatagramPacket. If your datagrams can be longer, make the buffer bigger.
Best practice is to make it one bigger than the largest datagram you are expecting to receive. Then if you receive one that size you have an application protocol error.

You should check on both client and server the length of the DatagramPacket after the send/receive operation respectively (with the getLength method) to make sure it's the same, that would be the first hint. What Collection are you using for names?

Your question is incomplete. However..
UDP loses packets. That's why it's not reliable to use UDP for File Transfer purposes. The Adobe RTMFP uses UDP to transfer audio and video data in which many packets are lost., But audio/video content streaming is really faster when compared to TCP. I don't know if this answers your question, I just want to say that UDP does lose packets.

Related

Java Udp sockets, packets lost in localhost

I am implementing a simple java udp socket program. Here are the details:
Server side: suppose I create 2500 packets in server side, then inform the client that i'm gonna send 2500 packets, and each packet is packetSize bytes. then in a loop, each packet is created and then sent.
Client side: after being informed of the number of packets, in a for (or while), I wait for 2500 packets to be received.
Here is the problem:
The for loop in client side never ends! that means 2500 packets are never received! Although I checked server side and it has sent them all.
I tried setting the socket's receive buffer size to 10 * packetSize using this:
socket.setReceiveBufferSize(10 * packetSize)
but it does not work.
How do you think I could solve this problem? I know UDP is not reliable but both client and server are running on different ports of the same computer!
Here is the code for server side:
for (int i = 0; i < packets; i++) {
byte[] currentPacket = new byte[size];
byte[] seqnum = intToByteArray(i);
currentPacket[0] = seqnum[0];
currentPacket[1] = seqnum[1];
currentPacket[2] = seqnum[2];
currentPacket[3] = seqnum[3];
for (int j = 0; j < size-4; j++) {
currentPacket[j+4] = finFile[i][j];
}
sendPacket = new DatagramPacket(currentPacket, currentPacket.length, receiverIP, receiverPort);
socket.send(sendPacket);
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
and the client side:
int k = 0;
while (true) {
receivedBytes = new byte[size];
receivePacket = new DatagramPacket(receivedBytes, size);
socket.receive(receivePacket);
allBytes.add(receivePacket.getData());
k++;
if (k == packets)
break;
}
allBytes is just a linked list containing received bytes. i use it to reassemble the final file.
P.S. This code works perfect for under 100Mb files.
Thanks
Update:
tl;dr summary: Either packets is not properly initialized or use TCP, or add a sequence number in your UDP packet so that your client knows if it drops a packet and you can write code to handle that (request for a rebroadcast). This essentially makes it a rudimentary TCP anyways.
I have a suspicion that you never initialized packets so you never hit your break. Rewriting your while into a for loop can easily check if this is true. Assuming the first packet you send contains how many packets it will be receiving, and you initialize packets correctly then if your packets are being lost then your client side program will not end since receive() is a blocking method.
If you strongly suspect that your packets are being lost, then debug your client side and see how many received packets are in your LinkedList and compare that against how many are sent on the server side.
for(int i = 0; i < packets; i++) {
receivedBytes = new byte[size];
receivePacket = new DatagramPacket(receivedBytes, size);
socket.receive(receivePacket);
allBytes.add(receivePacket.getData());
}
System.out.println("All " + packet + " received.");
Switching to code to the above will let you know that if you never get to the print statement, then you know that you're losing packets since receive() is a blocking method and it means that your client side is stuck in the for loop. This is because the for loop can't be satisfied since if the server sends 2500 packets but the client only receives 2300 packets, it'll still be in the for loop at the receive() line waiting for 2301, 2302, ... packets and so on.
Since you have a file with upwards of 100MB or more that needs to be assembled I assume you can't tolerate loss, so either use TCP that will fulfill that requirement or handle that possibility in your code by creating your own header with each packet. This header can be as simple as an incrementing sequence number that the client will receive and read, if it skips a number from the previous packet then it will know that a packet was lost. At this point, you can have your client request the server to rebroadcast that specific packet. But at this point you just implemented your own crude TCP.

Query an OpenTTD server

I am using the following java code to try to send a PACKET_UDP_CLIENT_FIND_SERVER (source) packet to query an OpenTTD server:
InetAddress address = InetAddress.getByName("publicserver-new.openttdcoop.org");
DatagramSocket socket = new DatagramSocket();
byte[] buf = new byte[]{0}; // 0 is number for CLIENT_FIND_SERVER, no extra data is needed (?)
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 3983);
socket.send(packet);
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
packet.getData(); //
socket.close();
However, when I run the program the server never returns any packets. I have very little experience working with packets, and have been trying to figure out what to do by looking at PHP and Python source code that does the same thing. Hopefully someone will be able to help.
Thanks
EDIT:
I realized that the packet should actually contain the data 03 00 00, the first two bytes contain the length, but I still haven't been able to get a response using a Packet Sender. Maybe I am listening on the wrong port?
I figured out what I had been doing wrong. This line:
byte[] buf = new byte[]{0};
should be:
byte[] buf = new byte[]{0x03, 0x00, 0x00} (hex for clarity)
The problem was that the first two bytes store the length of the data
The third byte is the actual request
In addition, the DatagamPacket needs to be reset to allow more than 3 bytes to be read

Read and Write Bytes data packet via socket

I want to connect Android Device to external device via Socket. Socket Connect to external device successfully.
Now if any data require from external device then send request of byte packet data to socket below order. if external device receive data correct then send byte data in response.
Parameters : methodname(1 byte), payloadlength(2 byte), payload(2 byte).
Now My Code is...
Socket socket = new Socket("local exteranl device ip", 5000);
if(socket.isConnected()) {
int methodname = 5;
int payload = 2151;
int payloadLength = 2;
ByteBuffer buffer = ByteBuffer.allocate(3 + payloadLength); // 3 = for method name + length
buffer.order(ByteOrder.BIG_ENDIAN); // Just to be explicit
buffer.put((byte) methodname);
buffer.putShort((short) payloadLength);
buffer.putShort((short) payload);
buffer.rewind();
byte[] result = new byte[buffer.capacity()]; // Could also use result = buffer.array();
buffer.get(result);
DataOutputStream classOUTstream = new DataOutputStream(socket.getOutputStream());
// socket is already connected
classOUTstream.write(result);
classOUTstream.flush();
InputStream stream = socket.getInputStream();
byte[] data = new byte[100];
int count = stream.read(data);
}
Above Code is Android, i knowing only basic concept of java. i am getting -1 result in count.
can any one please suggest me or tell me my mistake?
You're doing this the hard way. Get rid of the ByteBuffer altogether and use all the methods of DataOutputStream. They are all big-endian. I can't see any mistake but clearly you must be sending something the peer didn't understand so he is closing the connection instead of sending a reply.
Note: Socket.isConnected() cannot possibly be false at the point you're testing it.

getOffset() of a packet returns 0 on the receiver's end

I have a lengthy text file that I am trying to transport across UDP on localhost so naturally I have to break up the byte buffer to send the file in packets.
The problem I'm having is this:
On the server side, I send a packet of data with the offset into the byte buffer set to say 500:
byte[] buf = text.getBytes();
InetAddress address = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(buf, 500, BYTES_PER_PACKET, address, udp_port_num);
System.out.println("Offset at server: " + packet.getOffset());
udpSocket.send(packet);
The print statement returns the expected answer of 500.
But then on the client side:
byte[] buf = new byte[BYTES_PER_PACKET];
DatagramPacket packet = new DatagramPacket(buf, BYTES_PER_PACKET);
udpSocket.receive(packet);
String received = new String(packet.getData());
System.out.println(received);
System.out.println("Offset: " + packet.getOffset());
It prints the correct text from the offset of the file in received, but packet.getOffset() always returns 0. Why isn't it returning the same 500 from the server and/or how can I get it to return the same 500 from the server?
Thanks in advance
The meaning of all this is:
At the sender you created a DatagramPacket using bytes 500..BYTES_PER_PACKET-500 of the source array.
You sent the packet. It went over the wire as a UDP datagram. It arrived as a UDP datagram.
At the receiver, you constructed a new byte array, and constructed a new DatagramPacket around it, specifying offset = 0, or no offset parameter. You received into the DatagramPacket. Java put the UDP datagram into the byte array in the DatagramPacket, starting at the offset you specified: zero.
Note that the sender's DatagramPacket did not itself go over the wire, nor the sender's byte array either.

Failed to convert data from UDP packet into the initial data which is sent using Java

I'm writing a UDP Client to transfer a file to a UDP server. First I try to measure the length of the file, devided by the buffer length to be sent in UDP packet, to get the number of packets required to be sent. I send this number to the server first to acknowledge it. But on the server side, the transform from byte array of the receiving packet into the initial number just failed. Can anyone help me out of this? Here is my code on the client side:
DatagramSocket socket=new DatagramSocket();
File f = new File(filename);
long fileSize = f.length();
byte[] buffer = new byte[16384];
long packetNumber = (fileSize/(buffer.length))+1;
DatagramPacket sendPacket=new DatagramPacket(buffer,buffer.length,addr,srvPort);
String str=Long.toString(packetNumber);
buffer = str.getBytes();
socket.send(sendPacket);
And here is the code on the server side:
DatagramSocket socket=new DatagramSocket(port);
byte[] buffer=new byte[16384];
DatagramPacket receivePacket=new DatagramPacket(buffer, buffer.length);
while(true)
{
socket.receive(receivePacket);
if (receivePacket.getData().toString().trim()!=null)
{
String str=receivePacket.getData().toString();
System.out.println(str);
long pcount=Long.parseLong(str);
System.out.println(pcount+" packets to be received.");
break;
}
}
But on the server side the variable pcount can always not be resolved, and when I try to print out the str, it writes out some "[B#60991f" or sth, weird.
This code doesn't make any sense.
Most networks won't let you send a datagram over 534 bytes reliably.
At present you are sending 16384 bytes of zero value, because you aren't putting anything into the buffer: instead you are creating a new buffer after creating the DatagramPacket. So you aren't sending anything yet.
And you aren't receiving anything yet either. The result of String.trim() cannot be null. You must reset the byte array in a DatagramPacket before every receive(), because it shrinks to the size of the actual received packet, so unless you reset it it keeps getting smaller and smaller. The result of toString() on a byte array does not include its contents, so parsing it is futile.
You need to study several basic Java programming concepts: too many to answer here.
You're receiving a byte array, using toString() won't give you anything.
You should reconstruct the String from the bytes array using new String

Categories