Java UDP - Sending a string array from server to c

2019-09-23 10:24发布

问题:

Hi and thanks in advance,

So I'm trying to take an array of JList items and convert them to a string array (which I think I've gotten right), and then I'm trying to send that string array over to my client who will then attempt to display them back into a JList on their side.

I've tried a few different things but none are working.

Here is my latest code attempt to send the string array over:

String[] FilesList = (String[]) lClient1Files.getSelectedValues();

FilesBuffer = FilesList.getBytes();

DatagramPacket DGPFilesResponse = new DatagramPacket(FilesBuffer,FilesBuffer.length, DGP.getAddress(), DGP.getPort());
SeederSocket.send(DGPFilesResponse);

The line: FilesBuffer = FilesList.getBytes(); is causing the issue because getBytes() isn't applicable here.

So my questions are: 1) How do I send the array of JList items(they are names) over to the client (it doesn't particularly have to be a string array), and 2) How would I receive the list on the clients side, so that I can use it?

Thank you.

回答1:

One must make a binary format for the string array.

ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (DataOutputStream dos = new DataOutputStream(baos)) {
    dos.writeInt(filesList.length);
    for (String files : filesList) {
        dos.writeUTF(files);
    }
}
byte[] bytes = baos.toByteArray();

This internally for a String writes first the length in bytes, and uses String.getBytes("UTF-8") so any string can be written.

Reading goes with the reversed input classes.

If you think of having many clients out there, maybe with different versions, then add in the message a version number.


On the other side

ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
try (DataInputStream dis = new DataInputStream(baos)) {
    int stringsCount = dis.readInt();
    String[] filesList = new String[stringsCount];
    for (int i = 0; i < stringsCount; ++i) {
        filesList[i] = dis.readUTF();
    }
    return filesList;
}


回答2:

The UDP payload has to be a byte[]. You need to choose a way to encode your data into a byte[], such that it can be converted back at the receiving end.

So you need to write encode() and decode() so that unit tests like this work:

 @Test
 public void encodesAndDecodesStringArray() {
     String[] strings = new String[] { "foo", "bar" };
     byte[] encoded = Encoder.encode(strings);
     String[] decoded = Encoder.decode(encoded);

     assertThat(decoded, is(strings));
 }

There are literally hundreds of encoding schemes you could choose from. Delimiter-separated, length-separated, JSON, XML, BSON, ASN.1 ... take a look at Wikipedia's List of data serialization formats.

A very simple option that might work for you is delimiter-separation:

public byte[] encode(String[] strings) {
    return String.join(",", strings).getBytes(UTF_8);
}

public String[] decode(byte[] encodedArray) {
    return new String(encodedArray, UTF_8).split(",");
}

But note that this very basic scheme fails if any of the input strings contains a "," (or whatever delimiter you choose). Pick a scheme that works for you.

Consider using JSON -- there are easy to use libraries to read and write JSON. Readable ASCII in network traces is often convenient. The space overhead is not that high. It's ready for arbitrarily complex hierarchical data structures.

Consider that if you change the structure of the data produced by your sender, the receiver must also change. If that matters, consider encoding a protocol version into what you send (it might be enough to just say "the first two bytes are the version", and always stick a 0x0001 in there to start with).