BufferedInputStream hanging (not reaching end of file) - java

I have Java SSL/TLS server&client sockets. My client simply sends a file to the Server and Server receives it. Here are my codes:
My client method:
static boolean writeData(BufferedOutputStream bos, File data) {
FileInputStream fis = new FileInputStream(data);
BufferedInputStream bis = new BufferdInputStream(fis);
byte[] bytes = new byte[512];
int count = 0;
while ((count = bis.read(bytes, 0, bytes.length)) > 0) {
System.out.println("Sending file...");
bos.write(dataByte, 0, count);
System.out.println(count);
}
bos.flush();
System.out.println("File Sent");
}
My server method:
static boolean receiveData(BufferedInputStream bis, File data) {
byte[] bytes = new byte[512];
int count = 0;
while ((count = bis.read(bytes, 0, bytes.length)) > 0) {
System.out.println("Receiving file...");
// Do something..
System.out.println(count);
}
bos.flush();
System.out.println("File Received");
}
The problem is, the server hangs inside the while loop.. It never reaches the "File Received" message.
Even if the file is small, the bis.read() method never returns -1 at the end of file for some reason. I tested the methods with a file size of 16 bytes, and the output is as follows:
Client terminal:
> Sending file...
> 16
> File Sent
Server terminal:
> Receiving file...
> 16
As you can see, the server never reaches the "File Received" message and hangs inside the loop even after the end of stream is reached.. Can anyone guess the reason for this?
Thanks

Your server never detects that the file has been sent, because it checks whether you have closed the connection at the other end (the only reason why you would receive -1 bytes read).
But you never close the connection, you only flush it.
Replace bos.flush() with bos.close() in the writeData method and it should work.
If you don't want to close the connection, because you want to do more work with it, you have to add a protocol of some sort, because there is no default way to do that.
One thing you could do, which is one of the easier ways to implement this, is to send the length of the file as a 32-bit or 64-bit integer before the file.
Then the server knows how many bytes it should read before it can consider the file fully sent.
If you don't know the length of the file, there are many options. I'm not sure if there is a consensus on the most effective way to do this, but given that many protocols take different approaches, I don't think that there is.
These are just a few suggestions, which you can tune.
Before any piece of data, you send the length of the data you want to send as a 32-bit bit (signed) integer. So a file will be sent as multiple pieces of data. Sending a negative number means that the previous piece was the last piece and the file has ended. (If you needed to send a piece that was larger than the maximum that you can represent in a signed 32-bit integer, you need to split it in several pieces).
You think of a random number, with a long-enough length (something like 16 bytes or 32 bytes) that it will never occur in your data. You send that number before the file and when the file is done, you send it again to indicate that event. This is similar to the MIME multi-part encoding.
You take a byte or a number of bytes that indicates whether the file has ended (like 0xFF). But to ensure that you can still legitimately send 0xFF as part of the file, you add the rule that 0xFF 0xFF means that the file has ended, but 0xFF 0x00 means "just a literal 0xFF" in the file.
There are many more ways to do it.

Related

Transfer data from ReadableByteChannel to file

Goal: Decrypt data from one source and write the decrypted data to a file.
try (FileInputStream fis = new FileInputStream(targetPath.toFile());
ReadableByteChannel channel = newDecryptedByteChannel(path, associatedData))
{
FileChannel fc = fis.getChannel();
long position = 0;
while (position < ???)
{
position += fc.transferFrom(channel, position, CHUNK_SIZE);
}
}
The implementation of newDecryptedByteChannel(Path,byte[]) should not be of interest, it just returns a ReadableByteChannel.
Problem: What is the condition to end the while loop? When is the "end of the byte channel" reached? Is transferFrom the right choice here?
This question might be related (answer is to just set the count to Long.MAX_VALUE). Unfortunately this doesn't help me because the docs say that up to count bytes may be transfered, depending upon the natures and states of the channels.
Another thought was to just check whether the amount of bytes actually transferred is 0 (returned from transferFrom), but this condition may be true if the source channel is non-blocking and has fewer than count bytes immediately available in its input buffer.
It is one of the bizarre features of FileChannel. transferFrom() that it never tells you about end of stream. You have to know the input length independently.
I would just use streams for this: specifically, a CipherInputStream around a BufferedInputStream around a FileInputStream, and a FileOutputStream.
But the code you posted doesn't make any sense anyway. It can't work. You are transferring into the input file, and via a channel that was derived from a FileInputStream, so it is read-only, so transferFrom() will throw an exception.
As commented by #user207421, as you are reading from ReadableByteChannel, the target channel needs to be derived from FileOutputStream rather than FileInputStream. And the condition for ending loop in your code should be the size of file underlying the ReadableByteChannel which is not possible to get from it unless you are able to get FileChannel and find the size through its size method.
The way I could find for transferring is through ByteBuffer as below.
ByteBuffer buf = ByteBuffer.allocate(1024*8);
while(readableByteChannel.read(buf)!=-1)
{
buf.flip();
fc.write(buf); //fc is FileChannel derived from FileOutputStream
buf.compact();
}
buf.flip();
while(buf.hasRemainig())
{
fc.write(buf);
}

Trying to write and read from the same com port, successful at writing, but failing at reading. Wat do?

I'm trying to get some data from the com port, the same one I'm writing data on, but it proves hard to read. I managed to find a simple code piece to read it, but now, I only read zeros. What could be the cause?
I'm sending my code below, with explanation of their intended usages.
private void ReadFromComPortActionPerformed(java.awt.event.ActionEvent evt) {
try {
String text = EmulatorInput.getText();
sendData(text, "COM4");
String out_Text = Arrays.toString(read());
EmulatorOutput.setText(out_Text);
System.out.println(out_Text);
} catch (IOException ex) {
Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
}
}
This is a JButton, method name and parameter has been created by NetBeans. Code firsts gets a text from the input panel as a string, sends it with a com port name, connects to that port, and opens input/output streams by it, then writes the string it took from the input panel to the OutputStream. Then, I create a new string, named out_Text and use read() method to read the data from port.
Here is the read method;
private byte[] read() throws IOException {
byte[] buffer = new byte[16];
int total = 0, read = 0;
while (total <= 16 && (read = input.read(buffer, total, 16-total)) > 0) {
total += read;
}
return buffer;
}
After the first method I posted uses read() to converge it into a string that I can print as a byte array, I end up with only a byte of zeros.
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
I'm very confused by this, because I'm sure I write to the port. I even monitored what I write, and can see that as I use the program to write data to the com port, the data it received increases.
If there is something that is unclear or if you need more of the code, please contact via comments.
Thank you kindly.
After several tries, I've tried the same operation with jSSC, and managed to write again. However, I was still not able to read. Then I noticed, that I was creating pairs of com ports. So, simply, I started to write to one port, and received the data from the other port of the pair. It worked like a charm. I'm not sure if the same idea is valid for rxtx libraries, but because jSSC's documents are descriptive, and because it's easy to use, I switched to it, and the way I did worked. You can find a detailed explanation of how I did below, without the code.
PreStep > I had COM6 and COM7 intact when I started this.
Step1 > Opened both ports via jSSC's methods. I constructed them as SerialPort, and then set their parameters (BaudRate, DataBits, etc.).
Step2 > I started to take inputs from console, and write them to the COM6. When I monitored the port, and the bytes in it, it was changing each time I sent an input.
Step3 > Each time I would press "Enter" to send the input, I'd invoke a reading method from COM7 object, and it would send a byte array to the console (Via Arrays.toString(byte[] array) method).
I don't know why I can't read from the same port as I write, but alas, my problem is solved. Thanks for your time to read this answer. If you have any questions, please post them under this one as a comment.

Send binary file from Java Server to C# Unity3d Client with Protocol Buffer

I have asked this question https://stackoverflow.com/questions/32735189/sending-files-from-java-server-to-unity3d-c-sharp-client but I saw that it isn't an optimal solution to send files between Java and C# via built-in operations, because I also need also other messages, not only the file content.
Therefore, I tried using Protobuf, because it is fast and can serialize/deserialize objects platform independent. My .proto file is the following:
message File{
optional int32 fileSize = 1;
optional string fileName = 2;
optional bytes fileContent = 3;
}
So, I set the values for each variable in the generated .java file:
file.setFileSize(fileSize);
file.setFileName(fileName);
file.setFileContent(ByteString.copyFrom(fileContent, 0, fileContent.length);
I saw many tutorials about how to write the objects to a file and read from it. However, I can't find any example about how to send a file from server socket to client socket.
My intention is to serialize the object (file size, file name and file content) on the java server and to send these information to the C# client. So, the file can be deserialized and stored on the client side.
In my example code above, the server read the bytes of the file (image file) and write it to the output stream, so that the client can read and write the bytes to disk through input stream. I want to achieve the same thing with serialization of my generated .proto file.
Can anyone provide me an example or give me a hint how to do that?
As described in the documentation, protobuf does not take care of where a message start and stops, so when using a stream socket like TCP you'll have to do that yourself.
From the doc:
[...] If you want to write multiple messages to a single file or stream, it is up to you to keep track of where one message ends and the next begins. The Protocol Buffer wire format is not self-delimiting, so protocol buffer parsers cannot determine where a message ends on their own. The easiest way to solve this problem is to write the size of each message before you write the message itself. When you read the messages back in, you read the size, then read the bytes into a separate buffer, then parse from that buffer. [...]
Length-prefixing is a good candidate. Depending on what language you're writing, there are libraries that does length-prefixing for e.g. TCP that you can use, or you can define it yourself.
An example representation of the buffer on the wire might beof the format might be (beginning of buffer to the left):
[buf_length|serialized_buffer2]
So you code to pack the the buffer before sending might look something like (this is in javascript with node.js):
function pack(message) {
var packet = new Buffer(message.length + 2);
packet.writeIntBE(message.length, 0, 2);
message.copy(packet, 2);
return packet;
}
To read you would have to do the opposite:
client.on('data', function (data) {
dataBuffer = Buffer.concat([dataBuffer, data]);
var dataLen = dataBuffer.readIntBE(0, 2);
while(dataBuffer.length >= dataLen) {
// Message length excluding length prefix of 2 bytes
var msgLen = dataBuffer.readIntBE(0, 2);
var thisMsg = new Buffer(dataBuffer.slice(2, msgLen + 2));
//do something with the msg here
// Remove processed message from buffer
dataBuffer = dataBuffer.slice(msgLen + 2);
}
});
You should also be aware of that when sending multiple protobufs on a TCP socket, they are likely to be buffered for network optimizations (concatenated) and sent together. Meaning some sort of delimiter is needed anyway.

Sending images through a socket using qt and read it using java

I'm trying to send an image upload in a Qt server trough the socket and visualize it in a client created using Java. Until now I have only transferred strings to communicate on both sides, and tried different examples for sending images but with no results.
The code I used to transfer the image in qt is:
QImage image;
image.load("../punton.png");
qDebug()<<"Image loaded";
QByteArray ban; // Construct a QByteArray object
QBuffer buffer(&ban); // Construct a QBuffer object using the QbyteArray
image.save(&buffer, "PNG"); // Save the QImage data into the QBuffer
socket->write(ban);
In the other end the code to read in Java is:
BufferedInputStream in = new BufferedInputStream(socket.getInputStream(),1);
File f = new File("C:\\Users\\CLOUDMOTO\\Desktop\\JAVA\\image.png");
System.out.println("Receiving...");
FileOutputStream fout = new FileOutputStream(f);
byte[] by = new byte[1];
for(int len; (len = in.read(by)) > 0;){
fout.write(by, 0, len);
System.out.println("Done!");
}
The process in Java gets stuck until I close the Qt server and after that the file generated is corrupt.
I'll appreciate any help because it's neccessary for me to do this and I'm new to programming with both languages.
Also I've used the following commands that and the receiving process now ends and show a message, but the file is corrupt.
socket->write(ban+"-1");
socket->close(); in qt.
And in java:
System.out.println(by);
String received = new String(by, 0, by.length, "ISO8859_1");
System.out.println(received);
System.out.println("Done!");
You cannot transport file over socket in such simple way. You are not giving the receiver any clue, what number of bytes is coming. Read javadoc for InputStream.read() carefully. Your receiver is in endless loop because it is waiting for next byte until the stream is closed. So you have partially fixed that by calling socket->close() at the sender side. Ideally, you need to write the length of ban into the socket before the buffer, read that length at receiver side and then receive only that amount of bytes. Also flush and close the receiver stream before trying to read the received file.
I have absolutely no idea what you wanted to achieve with socket->write(ban+"-1"). Your logged output starts with %PNG which is correct. I can see there "-1" at the end, which means that you added characters to the image binary file, hence you corrupted it. Why so?
And no, 1x1 PNG does not have size of 1 byte. It does not have even 4 bytes (red,green,blue,alpha). PNG needs some things like header and control checksum. Have a look at the size of the file on filesystem. This is your required by size.

What could lead to the creation of false EOF in a GZip compressed data stream

We are streaming data between a server (written in .Net running on Windows) to a client (written in Java running on Ubuntu) in batches. The data is in XML format. Occasionally the Java client throws an unexpected EOF while trying decompress the stream. The message content always varies and is user driven. The response from the client is also compressed using GZip. This never fails and seems to be rock solid. The response from the client is controlled by the system.
Is there a chance that some arrangement of characters or some special characters are creating false EOF markers? Could it be white-space related? Is GZip suitable for compressing XML?
I am assuming that the code to read and write from the input/output streams works because we only occasionally gets this exception and when we inspect the user data at the time there seems to be special characters (which is why I asked the question) such as the '#' sign.
Any ideas?
UPDATE:
The actual code as requested. I thought it wasn't this due to the fact that I had been to a couple of sites to get help on this issue and they all more or less had the same code. Some sites mentioned appended GZip. Something to do with GZip creating multiple segments?
public String receive() throws IOException {
byte[] buffer = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
do {
int nrBytes = in.read(buffer);
if (nrBytes > 0) {
baos.write(buffer, 0, nrBytes);
}
} while (in.available() > 0);
return compressor.decompress(baos.toByteArray());
}
public String decompress(byte[] data) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(data);
try {
GZIPInputStream inflater = new GZIPInputStream(in);
byte[] byteBuffer = new byte[8192];
int r;
while((r = inflater.read(byteBuffer)) > 0 ) {
buffer.write(byteBuffer, 0, r);
}
} catch (IOException e) {
log.error("Could not decompress stream", e);
throw e;
}
return new String(buffer.toByteArray());
}
At first I thought there must be something wrong with the way that I am reading in the stream and I thought perhaps I am not looping properly. I then generated a ton of data to be streamed and checked that it was looping. Also the fact they it happens so seldom and so far has not been reproducable lead me to believe that it was the content rather than the scenario. But at this point I am totally baffled and for all I know it is the code.
Thanks again everyone.
Update 2:
As requested the .Net code:
Dim DataToCompress = Encoding.UTF8.GetBytes(Data)
Dim CompressedData = Compress(DataToCompress)
To get the raw data into bytes. And then it gets compressed
Private Function Compress(ByVal Data As Byte()) As Byte()
Try
Using MS = New MemoryStream()
Using Compression = New GZipStream(MS, CompressionMode.Compress)
Compression.Write(Data, 0, Data.Length)
Compression.Flush()
Compression.Close()
Return MS.ToArray()
End Using
End Using
Catch ex As Exception
Log.Error("Error trying to compress data", ex)
Throw
End Try
End Function
Update 3: Also added more java code. the in variable is the InputStream return from socket.getInputStream()
It certainly shouldn't be due to the data involved - the streams deal with binary data, so that shouldn't make any odds at all.
However, without seeing your code, it's hard to say for sure. My first port of call would be to check anywhere that you're using InputStream.read() - check that you're using the return value correctly, rather than assuming a single call to read() will fill the buffer.
If you could provide some code, that would help a lot...
I would suspect that for some reason the data is altered underway, by treating it as text, not as binary, so it may either be \n conversions or a codepage alteration.
How is the gzipped stream transferred between the two systems?
It is not pssible. EOF in TCP is delivered as an out of band FIN segment, not via the data.

Categories

Resources