I have hypothetical data coming from a UDP connection that is in binary form.
Its composed of 5 fields, with a size of 25 bits
their offsets as follows
1. 0-4 ID
2. 5-10 payload
3. 11-12 status
4. 13-23 location
5. 23-25 checksum
How do I read in this data?
DatagramSocket serverSocket = new DatagramSocket(18000);
byte[] receiveData = new byte[1024];
while (true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
//not sure how I should be reading the raw binary data back in
}
How would I store off this data?
DatagramPacket's getData returns the payload as a byte[]. You can use Arrays.copyOfRange to get the individual fields (I'm assuming you meant bytes in your question, not bits):
while (true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
// get the entire content
byte telegramContent[] = receivePacket.getData();
// and slice it up:
byte ID[] = Arrays.copyOfRange(telegramContent,0,5);
byte payload[] = Arrays.copyOfRange(telegramContent,6,11);
// and so on.
}
After this step you'll have your fields as individual byte arrays, probably some postprocessing/reassembly into other types will be necessary. During this step probably the most annoying thing is that all Java's types are signed whereas in many communication protocols unsigned entities are used, so be careful during this step.
Not mentioned in your question but you might need it later on: assembly of messages for transmission. I like to use GNU Trove's TByteArrayList for that task as you don't need to worry about reserving a byte[] with the correct length before you start, just copy in bytes or message segements and once you're done call toArray and voilĂ , your byte[] is ready for transmission.
Related
I have a java program written that simply receives data sent through a UDP socket and prints it to the screen. The data that is received is sent from another computer that uses matlab to send the data. I am pretty sure that the matlab simulation is fine because all it does is take a constant value of 2 with a double data type, uses a byte packer to pack the data and sends it through a UDP block to the specified IP Address and port. I concurrently run the java code on another pc which receives the data packet as a byte array of length 1024.
The data is received just fine, however the value that is constantly printed is
4.7783097267364807 E -299.
I am not sure if my code is grabbing the desired data from the packet correctly or if the ByteBuffer.wrap(.....).getDouble() function is used correctly. Any help would be greatly appreciated
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
class receiver
{
public static void main(String args[]) throws Exception
{
DatagramSocket serverSocket = new DatagramSocket(1024);
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
System.out.println("Listening...");
while(true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
double data = ByteBuffer.wrap(receiveData).getDouble();
System.out.println(data);
}
}
}
Your code is correct given the specification, but Matlab is sending you 0x0200000000000000 (or something shorter: see below). The big-endian representation of 2.0 as a double is 0x4000000000000000, so they are certainly not sending you a double.
To get 2 from what they're actually sending you, do this:
ByteBuffer bb = ByteBuffer.wrap(receivePacket.getData(), 0, receivePacket.getLength());
bb.order(ByteOrder.LITTLE_ENDIAN);
Then try the following, separately, in this order, until one works:
long l = bb.getLong();
int i = bb.getInt();
short s = bb.getShort();
byte b = bb.getByte();
without a buffer underflow. The way you're wrapping the buffer you are ignoring the datagram length, so it is impossible to tell whether they are sending one, two, four, or eight bytes.
Java Client
byte[] aReceiveData = new byte[1024];
DatagramPacket aReceivePacket = new DatagramPacket(aReceiveData, aReceiveData.length);
aServerSocket.receive(aReceivePacket);
ByteArrayInputStream aInput = new ByteArrayInputStream(aReceiveData);
Message test = Message.parseDelimitedFrom(aInput);
error
"Protocol message contained an invalid tag (zero)."
Python Server
mensagem = estoque_pb2.Message()
mensagem.type=1
mensagem.id=requestId
mensagem.methodId="test"
mensagem.obfReference="objectRef"
mensagem.arguments=resultado
return mensagem.SerializeToString()
self.udp.sendto(mensagem,self.client)
I am not able to send data from python to java using protobuf, thanks any help!
The received packet can be smaller than 1024 bytes, so one have to create ByteArrayInputStream only on received range of bytes.
The method parseDelimitedFrom intended to parse delimited messages. In fact it reads message length, and then reads message itself. As far, as I understood, your buffer contains only the message. Therefore, you have to use parseFrom method.
byte[] data = new byte[1024];
DatagramPacket pkt = new DatagramPacket(data, data.length);
socket.receive(pkt);
ByteArrayInputStream input = new ByteArrayInputStream(pkt.getData(), pkt.getOffset(), pkt.getLength());
Message test = Message.parseFrom(input);
How can i send a buffer of data whose length is 1 MB over socket in java.
What exactly i am doing is that i want to calculate upload speed of network.For that i want to send 1 MB data to server which i have written in C.
In C to receive and send data we have functions like send and recv through which we can send the desired number of bytes by passing the number of bytes to be sent.
send(connfd , client_message , `Bytes to send`, 0);
but in java i am able to send only 1 byte at a time using
int buffer[] = new int[1048576];
PrintWriter output1 = new PrintWriter(socket.getOutputStream(), true);
output1.print(buffer[1]);
so to send multiple bytes i need to call above function again and again. Is there any way in which i can pass whole buffer of 1048576 in on go.
Your PrintWriter has a print(char[] s) method (see doc). So you could instead create a new char array with the corresponding size (note: a char in Java is 2 byte long) and send that char array using that method.
But there is a better option: A look into the doc tells us we get an OutputStream from our socket. We could wrap that into a BufferedOutputStream, like this:
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte buffer[] = new byte[1024*1024];
bos.write(buffer, 0, buffer.length);
And then use bos.write(byte[], int, int) to directly send a byte array, which probably would be the most direct way to achieve what you want.
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
my assignment includes sending an image file using UDP service (using java I implemented that successfully). My professor asked to include:
"The exchanged data messages must also have a header part for the sender to include 16-bit message sequence number for duplicate filtering at the receiver end"
How to do this?
I assume to create your UDP packet, you are using a ByteArrayOutputStream to generate the data. If that is the case, just Wrap a DataOutputStream on top of that ByteArrayOutputStream, and call writeInt(somesequenceNumber) before writing the image data to the stream.
on the receive side, do the opposite, wrap a DataInputStream around a ByteArrayInputStream, and call readInt() to get the sequence number. From there you can check whether you have already received this packet.
Something like
Write Side
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(sequenceNumber++);
dos.writeInt(imageDataLength);
dos.write(imageData);
dos.flush();
byte[] udpPacketBytes = baos.toByteArray();
Read Side
ByteArrayInputStream bais = new ByteArrayInputStream(udpPacketBytes);
DataInputStream dis = new DataInputStream(bais);
int sequenceNumber = dis.readInt();
if (seenSequenceNumbers.add(Integer.valueOf(sequenceNumber)))
{
int imageLength = dis.readInt();
byte[] imageData = new byte[imageLength];
dis.read(imageData);
}
where seenSequenceNumbers is some Set
For a 16-bit value I would use DataOutputStream.writeShort() and DataInputSTream readShort()/readUnsignedShort(). writeInt() and readInt() are for 32-bit values. If you want to avoid duplicates, a 32-bit value may be a better choice in any case. ;)