How to read from byte stream in Java (PHP/Java socket communication) - java

So. I have a PHP socket server and Java socket client.
Maybe it's a stupid question... but i didn't find an answer.
In client, i need to read incoming bytes from input stream and put them into byte array.
I tried to do so:
[CLIENT (Java)]
public static byte[] read(BufferedInputStream in)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[32768];
while (true) {
int readBytesCount = in.read(buffer);
if (readBytesCount == -1) {
break;
}
if (readBytesCount > 0) {
baos.write(buffer, 0, readBytesCount);
}
}
baos.flush();
baos.close();
return baos.toByteArray();
}
[SERVER (PHP)]
function write(&$client, $message)
{
$message = explode("\n", $message);
foreach ($message as $line)
{
socket_write($client['sock'], $line."\0");
}
}
But when it read all bytes, in.read() doesn't return -1, so the cycle doesn't stop.
One time it returns 13 (length) and then - nothing.
Any ideas?
SOLVED!
[CLIENT (Java)]
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[32768];
while (true) {
int readBytesCount = in.read(buffer);
if (getString(buffer).contains("#!EOS!#")) {
baos.flush();
baos.close();
return baos.toByteArray();
}
if (readBytesCount > 0) {
baos.write(buffer, 0, readBytesCount - 1);
}
}
[SERVER (PHP)]
function write(&$client, $message)
{
$message = explode("\n", $message);
$message = str_replace("\r", "", $message);
foreach ($message as $line)
{
rLog("Write to ".$client['ip'].": ".$line);
socket_write($client['sock'], $line."\0") or die("[".date('Y-m-d H:i:s')."] Could not write to socket\n");
}
socket_write($client['sock'], "#!EOS!#");
}

If your socket is still opened I believe that read will never retun -1. You do not close the trasmission ( in terms of file an EOF is not reached ). I believe that your read call returns 0 when your message is end ( instead of -1 ).
Java docs:
Read returns:
* The specified number of bytes have been read,
* The read method of the underlying stream returns -1, indicating end-of-file, or
* The available method of the underlying stream returns zero, indicating that further input requests would block.
So I believe you need to send a terminating character sequence, or the number of characters you will send, in order to identify on client-side the boundaries of your chunk of data ( the message ) inside the streaming of data.

I agree with Stefano. No EOF or terminate signal is happening on the php server side. socket_write is just writing $message to the client side. If your intent is to terminate the connection after the entire message has been written, then you might have to explicitly use socket_shutdown/socket_close.
You can also try socket_send with flags. Here is the doc for that http://www.php.net/manual/en/function.socket-send.php

Related

program hangs inside while loop for reading input stream from socket: Java

I have the following code to read an input stream from a socket connection:
private ByteBuffer toByteBuffer(BufferedInputStream is) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int l;
byte[] data = new byte[256];
while ((l = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, l);
}
buffer.flush();
return ByteBuffer.wrap(buffer.toByteArray());
}
In the first iteration of the while loop, everything goes fine and I am able to get the data into the buffer. But then it gets stuck at while ((l = is.read(data, 0, data.length)) != -1) {
I think (and I might be wrong) it is because it is waiting for more data from the socket, which is never going to come.
How do I handle this situation/hang?
As the BufferedInputStream method you are using does not block you get the situation that as soon as your InputStream does not have any data and is not closed you don't get a -1 but a 0.
This will send your method into an endless loop.
So for reading local streams it is better to check for read() <= 0 as you usually get the data fast enough.The best way is to make sure there is an eof by closing the stream.

Send file length with outputstream and receive length and byte[] with inputstream for streaming frames from one device to the other Android/Java

I have searched and searched and everything I have found has been helpful but I keep getting an out of memory error. The images I send are .06 MB so I know the problem isn't from decoding the byte[] into a bitmap. When I remove the while loops this works like a charm for one frame but I want multiple frames. I am getting a byte[] and sending it to a different device using sockets but I am at a loss how to do this. My problem is that I don't send and receive the correct byte[] length. This is what i am doing currently.
while (count != -1) {
//first send the byte[] length
dataOutputStream.writeInt(sendPackage.length);
//pass a byte array
publishProgress("sending file to client");
showMyToastOnUiThread(String.valueOf(sendPackage.length));
outputStream.write(sendPackage, 0, sendPackage.length);
outputStream.flush();
}
Receive byte[] on different device:
int count = inputStream.read();
while (count != -1) {
int byteArrayLength = dataInputStream.readInt();
Log.i(MainActivity.TAG, "Starting convert to byte array");
byte[] receivedBytes = convertInputStreamToByteArray(inputStream, byteArrayLength);
Bitmap bitmap = BitmapFactory.decodeByteArray(receivedBytes, 0, receivedBytes.length);
publishProgress(bitmap);
}
//convert inputstream to byte[]
public byte[] convertInputStreamToByteArray(InputStream inputStream, int readLength) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] data = new byte[readLength];
try {
Log.i(MainActivity.TAG, "Starting convert to byte array while loop");
int readTotal = 0;
int count = 0;
while (count >= 0 && readTotal < readLength) {
count = inputStream.read(data, readTotal, readLength - readTotal);
if (readLength > 0) {
readTotal += count;
}
}
Log.i(MainActivity.TAG, "Finished convert to byte array while loop");
} catch (IOException e) {
Log.e(MainActivity.TAG, "error: " + e.getMessage());
e.printStackTrace();
}
return data;
}
This is the problem:
int count = inputStream.read();
while (count != -1) {
You're consuming a byte and then ignoring it. That means the next value you read (the size) will be incorrect. You need a different way of telling whether you're at the end of the stream. Some options:
Send a -1 when you're finished; that way you can stop as soon as readInt returns -1
If you know it, send the number of images you're going to send before you start sending them
Use mark(1), then read(), then reset() - if your stream supports marking. I don't know whether it will or not. You could always wrap it in BufferedInputStream if not.
Reimplement DataInputStream.readInt yourself in a way which detects the end of the stream as being an expected possibility instead of throwing an exception
Just catch an exception in readInt (not nice - getting to the end of the stream isn't really exceptional)

InputStream receive method blocking

I am stuck with the following problem. I have created a connection to a remote echo server. The following method is used for receiving the bytes received from the server:
public byte[] receive() {
byte[] resultBuff = new byte[0];
byte[] buff = new byte[4096];
try {
InputStream in = socket.getInputStream();
int k = -1;
while((k = in.read(buff, 0, buff.length)) != -1) {
System.out.println(k);
byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
System.arraycopy(buff, 0, tbuff, resultBuff.length, k); // copy current lot
resultBuff = tbuff; // call the temp buffer as your result buff
String test = new String(resultBuff);
System.out.println(test);
}
System.out.println(resultBuff.length + " bytes read.");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resultBuff;
}
I am able to get the following response from the server:
Connection to MSRG Echo server established
The problem is that the loop gets stuck at the second execution on in.read(). I understand that this is due the the server not sending any EOF info and the like.
I am not sure which of the following two solutions is correct and in which way to implement it:
Each message coming from the server will be read by a new execution of the receive() method. How do I prevent the in.read() method from blocking?
The loop inside the receive() method should be kept alive until application exit. This means that my implementation is currently using in.read() wrong. In which way should this be implemented.
The key to this question is your use of the word 'message'. There are no messages in TCP, only a byte stream. If you want messages you must implement them yourself: read a byte at a time until you have a complete message, process it, rinse and repeat. You can amortize the cost of the single-byte reads by using a BufferedInputStream.
But there are no messages in an echo server. Your read and accumulate strategy is therefore inappropriate. Just echo immediately whatever you received.

Why my java socket can't end itself?

Here is my code snippet:
BufferedInputStream in = new BufferedInputStream(
server.getInputStream());
LittleEndianDataInputStream ledis = new LittleEndianDataInputStream(
in);
byte[] contents = new byte[1024];
System.out.println("45");
int bytesRead = 0;
String s;
while ((bytesRead = ledis.read(contents)) > 0) {
System.out.println(bytesRead);
s = new String(contents, 0, bytesRead);
System.out.print(s);
}
System.out.println("53");
After my client send the message to the socket, and the programme successfully print the result, but I can't print the 53, until I stop the client socket's connection. What should I do to deal with it? My client is an async socket. Thanks.
Your while-loop ends, when it gets an EOF and an EOF is sent from the writing side, whenever you either close the socket or - more graceful - shutdown the output.
So, in your case, your while-loop will end, when the sending side calls socket.shutdownOutput(). This closes just the output stream and puts an EOF at the end of the data.
I'm pretty sure this was discussed before, unfortunately I cannot find the question any more to just link. From the top of my head, the writing side should run the following code to close the connection gracefully:
// lets say the output stream is buffered, is namend bos and was created like this:
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
// Then the closing sequence should be
bos.flush();
socket.shutdownOutput(); // This will send the EOF to the reading side
// And on the reading side at the end of your code you can close the socket after getting the EOF
....
while ((bytesRead = ledis.read(contents)) > 0) {
System.out.println(bytesRead);
s = new String(contents, 0, bytesRead);
System.out.print(s);
}
System.out.println("53");
server.close; // <- After EOF was received, so no Exception will be thrown

Socket Inputstream doesn't return -1 at the end of stream

This is a code snippet where the problem is happening:
public static byte[] copyLargeExt(InputStream input) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024*8];
int n = 0;
while(-1 != (n = input.read(buffer))) {
baos.write(buffer, 0, n);
// i just append this pattern ({###END###}) to force the break
/*if(baos.toString(UTF8.name()).endsWith("{###END###}")) {
break;
}*/
}
return baos.toByteArray();
}
Can someone help me?
The code in the question reads to the end of the socket stream. If the method is blocking and in the read call, then that can only mean that the other end has not closed its corresponding output stream yet.
You have two choices:
Change the other end to close its outputstream so that this code will see an EOF.
Change the "protocol" so that this code knows how many bytes of data to expect ... and reads exactly that number of bytes.
In Java.
If the Server only Socket.close() without OutputStream.close() first, the Client's InputStream.read() will not return -1.
Instead, the Client's InputStream.read() will block until timeout.
So the best practice on Server is:
OutputStream.close();
InputStream.close();
Socket.close();

Categories

Resources