Warm tip: This article is reproduced from serverfault.com, please click

Send and receive a w3c.dom.Document over socket as byte[] Java

发布于 2020-12-27 16:49:24

I send a document over socket like this:

sendFXML(asByteArray(getRequiredScene(fetchSceneRequest())));

 private void sendFXML(byte[] requiredFXML) throws IOException, TransformerException {
    dataOutputStream.write(requiredFXML);
    dataOutputStream.flush();
}

private Document getRequiredScene(String requiredFile) throws IOException, ParserConfigurationException, SAXException, TransformerException {
   return new XMLLocator().getDocumentOrReturnNull(requiredFile);
}

private String fetchSceneRequest() throws IOException, ClassNotFoundException {
    return dataInputStream.readUTF();
}

On the side of XMLLocator it finds the correct document and parses it right. I see it by printing the whole doc in console. But I cannot handle it on the clients side where it's fetch by:

public static void receivePage() throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] data = new byte[989898];

    int bytesRead = -1;
    while((bytesRead = dataInputStream.read(data)) != -1 ) { //stops here
        baos.write(data, 0, bytesRead );
    }

    Files.write(Paths.get(FILE_TO_RECEIVED), data);
}

After the first iteration in while() cycle it just stops on the commented place. I don't know if I have an error on the side of the server and I send this in doc in an incorrect format or I read the sent byte array incorrectly. Where is the problem?

Edit: For the debug purpose, in the receivePage() method, I've chosen a different way of reading the byte array from server which goes like:

    int count = inputStream.available();
    byte[] b = new byte[count];
    int bytes = dataInputStream.read(b);
    System.out.println(bytes);
    for (byte by : b) {
        System.out.print((char)by);
    }

And now I'm able to print fetched FXLM in console but a new problem has appeared. On debug, it normally receives the byte[] from server, writes 2024 for count and displayes the content of the file but if I run the app normally via Shift + f10 it fetches nothing and just writes 0 in console

Edit2: For some reason, once again, on debug, it's able to even write into a file

for (byte by : b) {
   Files.write(Paths.get(FILE_TO_RECEIVED), b);
   System.out.print((char)by);
}

But when I try to return this fxml on debug and then show like this:

Parent fxmlToShow = FXMLLoader.load(getClass().getResource("/network/gui.fxml"));
Scene childScene = new Scene(fxmlToShow);
Stage window = (Stage)((Node)ae.getSource()).getScene().getWindow();
window.setScene(childScene);
return window;

It shows only previous files. Like on the first attempt of debug it show a blank page when I asked for the 1st one from server. On the second attempt of debug when i ask for 3rd page from server, it shows me the previously asked one and so on. To me, it seems absolutely insane cuz the fxml rile actually refreshes before the line

Parent fxmlToShow = FXMLLoader.load(getClass().getResource("/network/gui.fxml"));

is invoked.

Questioner
63350541
Viewed
0
63350541 2020-12-29 23:53:10

Yeah, thank everybody for participating. So, the issue of incorrect displaying if FXML files was caused by the incorrect FILE_TO_RECEIVED path. When FXMLLoader.load(getClass().getResource("/network/gui.fxml")); loads gui.fxml it takes it not from D:\\JetBrains\\IdeaProjects\\Client\\src\\network\\gui.fxml,im my case, but from D:\\JetBrains\\IdeaProjects\\Client\\OUT\\PRODUCTION\\Client\\network\\gui.fxml. As for me, that doesn't seem obvious.

What about different behaviour on debug and on run. In method receivePage() it needs to wait until connection is available.

int count = inputStream.available();

If you read docs for this method you will see

Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream ... The available method for class InputStream always returns 0...

So, you jext need to wait for connection to be available

while(inputStream.available()==0){
        Thread.sleep(100);
}

Otherwise it just prepares byte[] b = new byte[count]; for 0 bytes and you can write in nothing.