Detect end of DataInputStream bytes not working (Java) - java

I'm using the class DataInputStream to read from a Socket. I must use the readByte (not readLine) because the input does not necessarily in String format. The problem is I must wait the end of the stream to call a function and I couldn't detect it.
The code:
reader = new DataInputStream(socket.getInputStream());
byte dt;
String cmd = "";
while( (dt = reader.readByte()) >= 0){
cmd += (char)dt;
if( /* end of the stream reached */ ){
processInput(cmd);
}
}
System.out.println("End of the loop");
The problem is I don't know how to write this if. And, the end of the loop is not being reached when the Stream ends, the proof of this is that the phrase "End of the loop" is never being printed, so it is just stuck on the loop

This is documented at readByte()
Throws:
EOFException - if this input stream has reached the end.
So in order to see end of file, you must use try/catch
try {
while(true){
cmd += (char) reader.readByte();
}
} catch (EOFException e) {
// handle EOF
}
/* end of the stream reached */
processInput(cmd);
System.out.println("End of the loop");
An alternative would be to use one of the read() functions, which return -1 when reaching end of file, e.g.
int dt;
while ((dt = reader.read()) >= 0) {
// ...
}
Using one of the other read(...) functions could be more efficient, since they return a buffer full of input.

Related

stdin not echoing on windows when read() called after available() checked (Interruptible readline implementation)

I'm trying to implement an interruptible readline method [1] in Java , because the standard routine (using a buffered reader around System.in) isn't. I've come up with a routine that works pretty well on Linux, but when you run it in Windows-land, the key-presses are not echoed to the console until the user presses enter - gah!
After some experimenting, it seems the key-presses are only echo'd if there's a blocking call to System.in.read() while the user types.
Does anyone know if this is fixable? I tried to reflect my way in to using the private java.ui.Console#echo method, but it didn't seem to do anything. My next port of call will be to have a look at the JNA API and see if I can get direct access to the console from there.
1 - For reference, here's my interruptible readline implementation. I capture ctrl-c and interrupt the thread that's calling readline - handled elsewhere, working, and probably not relevant for this example
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
public class EchoTest {
private static final long MILLIS_BETWEEN_STDIN_CHECKS = 10;
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("Type something");
// on windows, there's no echo until enter, dammit!
String input = readline(System.in);
System.out.println("Hello, " + input);
}
/**
* Read a line of input from an input stream, presumably stdin.
*
* #param stdin An InputStream to read a line from.
*
* #return the string that was read, with the line terminator removed.
*
* #throws IOException if there was an io error reading from stdin
* #throws InterruptedException if the thread was interrupted while waiting to receive keypresses
*/
public static String readline(InputStream stdin) throws IOException, InterruptedException {
// we use mark to peek ahead for \r\n
if (!stdin.markSupported()) {
throw new IllegalArgumentException("stdin must support mark");
}
// result is stored in here
StringBuffer stringBuffer = new StringBuffer(512);
// a byte buffer as we read a byte at a time from stdin
byte[] bytes = new byte[64];
// number of bytes we've read in to the buffer
int bytesRead = 0;
while (true) {
// check whether read should block
if (stdin.available() > 0) {
int byteRead = stdin.read();
if (byteRead == -1) {
// end of stream - not expected for readline
throw new EOFException();
}
// check for line ending character sequences, we need to detect \r, \n or \r\n
if (byteRead == '\n') {
// we're done!
break;
} else if (byteRead == '\r') {
// we're done, but we might need to consume a trailing \n
if (stdin.available() == 0) {
// nothing is ready, we presume that if \r\n was sent, then they'd be sent as one and the buffer would
// already have the \n
// worst case, the next call to readline will exit with an empty string - if this appears to happen, we
// could detect a \n being in stdin at the start and drop it on the floor
break;
} else {
// there is a byte there - mark our position and check if it's \n
stdin.mark(1);
if (stdin.read() == '\n') {
// it is we're done
break;
} else {
// it isn't \n, reset position for the next call to readline or read
stdin.reset();
break;
}
}
} else {
bytes[bytesRead++] = (byte)byteRead;
// flush buffer if it's full
if (bytesRead == bytes.length) {
stringBuffer.append(new String(bytes, 0, bytesRead));
bytesRead = 0;
}
}
} else {
if (Thread.interrupted()) {
throw new InterruptedException();
} else {
Thread.sleep(MILLIS_BETWEEN_STDIN_CHECKS);
}
}
}
stringBuffer.append(new String(bytes, 0, bytesRead));
return stringBuffer.toString();
}
}

Custom readLine() method for server/client communication

I'm writing a Server/Client application, where the server will be communicating with many different clients. The communication with each client is taking place in a separate thread on the machine running the server.
So far I have been using the BufferedReader class in order to read data from the client sockets using the readLine() method. The problem I have with readLine() is that it stops reading when it finds a new line character. Due to the nature of my program I would like to substitute the new line limitation with a sequence of characters like $^%, so with a readLine() call the BufferedReader will keep reading unitl it finds &^%. For example if a client tries to send a url or a filepath where \n can be found as part of the natural path the readLine() method will read the \n and stop reading further.
I have created the following class in an attempt to solve this problem. But I have now created an even bigger one. When I use the BufferedReader class and the readLine() method my Server can service a lot of clients, but when I use CustomBufferedReader and readCustomLine() the Server crashes after the 4 or 5 threads start running. I'm pretty sure my class is consuming lots of resources compared to readLine() but I have no idea, why or how.
I would appreciate any insight on the matter.
public class CustomBufferedReader extends BufferedReader {
public CustomBufferedReader(Reader reader) {
super(reader);
}
/**
* Keeps reading data from a socket and stores them into a String buffer until
* the combination of $^% is red.
*
* #return A String containing the buffer red without the $^% ending.
* #throws IOException
*/
public String readCustomLine() throws IOException {
//$^%
String buffer="";
try
{
if(super.ready())
{
//First I'm reading 3 bytes in order to have at least 3 bytes
//in the buffer to compare them later on.
try
{
buffer = buffer + (char)super.read();
buffer = buffer + (char)super.read();
buffer = buffer + (char)super.read();
}
catch (IOException e)
{
e.printStackTrace();
System.out.println(e.getMessage());
}
int i=0;
//This while well keep reading bytes and adding the to the buffer until it reads
//$^% as the terminating sequence of bytes.
while (!(buffer.charAt(i)=='$' && buffer.charAt(i+1)=='^' && buffer.charAt(i+2)=='%')){
try
{
buffer = buffer + (char)super.read();
i++;
}
catch (IOException e)
{
e.printStackTrace();
System.out.println(e.getMessage());
}
}
// Returns the saved buffer after subtracting the $^% ending.
return buffer.substring(0, buffer.length() - 3);
}
}
catch (IOException e)
{
//e.printStackTrace();
}
return buffer;
}
}
I think this is an easier way to achieve what you are looking for:
String line = new Scanner(reader).useDelimiter("$^%").next();
About why your implementation of readCustomLine is not working, you may have a concurrency problem. If you take a look at the readLine implementation of BufferedReader you may notice that all its code runs enclosed in a synchronized block. So you may try that in your code.
Also, If an Exception is thrown from super.read() you just catch it and keep going even though the resulting buffer will have errors, you can try removing the inner try/catch blocks.
Finally as EJP has pointed out, you should remove the ready() call and check every super.read() for a -1 (meaning EOF).
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
public class CustomBufferedReader extends BufferedReader {
public CustomBufferedReader(final Reader reader) {
super(reader);
}
/**
* Keeps reading data from a socket and stores them into a String buffer
* until the combination of $^% is read.
*
* #return A String containing the buffer read without the $^% ending.
* #throws IOException
*/
public synchronized String readCustomLine() throws IOException {
// $^%
String buffer = "";
try {
// First I'm reading 3 bytes in order to have at least 3 bytes
// in the buffer to compare them later on.
buffer = buffer + safeRead();
buffer = buffer + safeRead();
buffer = buffer + safeRead();
int i = 0;
// This while will keep reading bytes and adding them to the
// buffer until it reads $^% as the terminating sequence of bytes.
while (!(buffer.charAt(i) == '$' && buffer.charAt(i + 1) == '^'
&& buffer.charAt(i + 2) == '%')) {
buffer = buffer + safeRead();
i++;
}
// Returns the saved buffer after subtracting the $^% ending.
return buffer.substring(0, buffer.length() - 3);
} catch (IOException e) {
/*
* Personally, I would remove this try/catch block and let the
* exception reach the caller
*/
e.printStackTrace();
System.out.println(e.getMessage());
}
return buffer;
}
private char safeRead() throws IOException {
int value = super.read();
if (value == -1) {
throw new EOFException();
}
return (char) value;
}
}

Reading and Handling Streams

I want to read and handle a stream of String containing single OR multiple commands in one line.
I am currently using InputStream in = socket.getInputStream(); for my inputstream.
Also for handling the input a typical Thread:
public void run() {
String input = "";
try {
int data = 0;
while (!isInterrupted()) {
while ((data = in.read()) != -1 && !isInterrupted()) {
input += Integer.toHexString(data);
handleInput(input);
}
try {
sleep(500);
} catch (InterruptedException e) {
break;
}
}
socket.close();
return;
} catch (IOException e) {
main.log("Connection lost...");
main.log(e.toString());
main.stopBTCommunication();
main.startBTServer();
}
}
handleInput() is designed to handle any String given to it and response correctly. The problem with this implementation would be, that handleInput() is called with every byte read from in.read(). I know, that i could use BufferedReader.readLine(), but that would require every incomming command to have "\n" appended to it, which is NOT the case and can't be changed.
I know that
while (!isInterrupted()) {
while ((data = in.read()) != -1 && !isInterrupted()) {
is kind of nuisance, but basically it want the Thread to read until nothing new is read, then handle that input and then read again...
EDIT:
So basically, what i need is a non-blocking read().
EDIT2:
How can incoming commands and commandchains look like:
Select Command: "s"
ReadLine Command: "rlXX" whereby X is a Hex Digit
WriteLine Command: "wlXXSSSSSSSS" whereby X and S are Hex Digits
So a commandschain may look like one of the following:
"s"
"srlff" = "s" + "rlff"
"rlffwlbb2e2e2e2erlbb" = "s" + "rlff" + "wlbb2e2e2e2e" + "rlbb"
I don't think you really need a non-blocking read. You need a method that reads the stream byte by byte and translates it into commands as it goes.
Something like:
public void processStream(InputStream in) {
List<Command> commands = new ArrayList<Command>();
while((int c = in.getChar()) != -1 ) {
switch((char)c) {
case 's':
commands.add(new SelectCommand());
break;
case 'r':
commands.add(ReadCommand.buildFromStream(in));
break;
case 'w':
commands.add(WriteCommand.buildFromStream(in));
break;
case ';':
commandEngine.execute(commands);
break;
default:
throw new StreamParseError("unexpected character: " + c);
}
}
}
This assumes that SelectCommand, ReadCommand, WriteCommand are type-compatible with Command.
... with for example ReadCommand.buildFromStream being:
public static ReadCommand buildFromStream(InputStream in) {
if((char)in.read() != 'n') {
throw new StreamParseError("Expect 'l' after 'r'");
}
// bad error checking here - be less lazy in real life.
String hexNum = in.read() + in.read();
int num = Integer.parseInt(hexNum,16);
return new ReadCommand(num);
}
This is very primitive parsing, but it shows the principle. There are well established techniques for more advanced parsing, which you can read up on if you want to.
You could also use a Scanner. Most commonly, Scanner is used with delimiters, but it can also look for regex patterns.
Scanner scanner = new Scanner(stream);
String cmd = "";
while(cmd != "e") { // I made up an "end" command :)
cmd = scanner.findWithinHorizon("(s|rl..|wl.{8}|e)",12);
if(cmd == null) {
// end of input, or badly formed input
break;
}
handleCmd(cmd);
}
You can read in array of bytes like this
int bytesRead = 0;
byte[] buffer = new byte[1024]; // reads up to 1024 byte chunks
while((bytesRead = in.read(buffer)) != -1) {
for ( int i = 0; i < bytesRead; i++ ) {
input += Integer.toHexString(buffer[i]);
}
handleInput(input);
}
The above code calls is the same as your old code that "input" keeps growing and used over and over again to call handleInput(). No sure if this is your intention but it looks suspicious.
Note that you are reading data from a stream. This means that you will have to implement recovery of the commands' structure yourself, i.e. you must at least detect the beginning and end of a command in your own code.
This again leads to another problem: You have no guarantee about how your stream's data is split into "chunks" by the transport layer. You may receive one command plus half a command in one read(buffer) call and then the second half of the command plus some more data in the next read(buffer).
Therefore, what I recommend is that you keep reading data only until you detect the end of one message/command/whatever and then perform handling for only this single message, before reading more incoming data and repeating. Everything else (i.e. dealing with partially received messages) easily becomes messy.
EDIT - With this particular input/output, since you don't have a delimiter, Scanner may not be the way to go here, but if you've got a delimiter between commands, it would be a great option, so I'll keep the answer here in the hopes it might help someone in the future.
Since your example doesn't have a delimiter, I have to get a little bit hack-y to demonstrate scanner's awesomeness, but it should still work for the exact commands you've listed. It would not be a good choice if you expect the command vocabulary to change.
I'd really recommend the use of delimiters if at all possible. It makes life much easier.
I'd look at the Scanner class if I were you.
The Scanner can wrap your input stream, and then scan based on a regex or delimter to grab chunks of input. Then your handleInput() method can operate on chunks (whole commands) rather than individual bytes.
Here's a brief, standalone example:
package com.stackoverflow.q22199860;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.regex.Pattern;
public class ReadStream
{
public static void main(String[] args)
{
Pattern commandPattern = Pattern.compile("s|rl|wl");
String commands = "srlffwlbb2e2e2e2erlbb";
Charset utf8 = StandardCharsets.UTF_8;
try (
InputStream inputStream = new ByteArrayInputStream(commands.getBytes(utf8));
Scanner scanner = new Scanner(inputStream, utf8.name());
) {
scanner.useDelimiter(commandPattern);
while(scanner.hasNext()) {
String command = scanner.next();
if (command.isEmpty()){
//s
System.out.println("s" + command);
} else if (command.length() == 2) {
//rl
System.out.println("rl" + command);
} else if (command.length() == 10) {
//wl
System.out.println("wl" + command);
}
}
}
catch (IOException e)
{
System.err.println("Error Reading Stream");
}
}
}
The output from this is:
s
rlff
wlbb2e2e2e2e
rlbb

Java inputStream to String Hangs

I am developing a tool to get client information, send to a server, and receive the information again (a proxy). I'm also trying to dump the data being received from the server. I can read the Integer representation of the inputStream, but I am not able to read the String format. I've tried the below example, but it hangs and never connects to the server. Also, System.out.println(inputStream.nextLine()) displays only one line and hangs.
public void run() {
try {
int i;
while ((i = inputStream.read()) != -1){
System.out.println(IOUtils.toString(inputStream));
outputStream.write(i);
}
} catch (IOException e) {
System.out.println("Lost connection to the client.");
}
}
My guess at this is that you're reading from the input stream, and then using the IOUtils library to read from the stream too. My suspicion is that your application is reading the first byte from the input stream, then reading the remainder of the inputstream with the IOUtils library, and then printing out the initial byte that was read.
It doesn't make any sense to call IOUtils.toString(inputstream) from within a loop. That method call will put all the data from the inputstream into a string. Why have the loop at all in this case?
You might want to try not using the IOUtils library for this. Just read a byte of data, push it into a StringBuilder, and then print that byte. In this approach, the loop would be necessary, and you'll probably get what you're looking for.
Try something like this, but modify it as necessary to print the data at the same time to your output stream:
public static String inputStreamToString(final InputStream is, final int bufferSize)
{
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
try {
final Reader in = new InputStreamReader(is, "UTF-8");
try {
for (;;) {
int rsz = in.read(buffer, 0, buffer.length);
if (rsz < 0)
break;
out.append(buffer, 0, rsz);
}
}
finally {
in.close();
}
}
catch (UnsupportedEncodingException ex) {
/* ... */
}
catch (IOException ex) {
/* ... */
}
return out.toString();
}
The code you posted doesn't attempt to connect to the server, but if any of it executes you must already have connected.
If your program is hanging in this code, either the server hasn't sent any data yet, or the IOUtils.toString() method probably tries to read to EOS, so if the peer doesn't close the connection you will block here forever.
If your program hangs at a readLine() call it means the peer hasn't sent a line to read.

Java, need a while loop to reach eof. i.e.while !eof, keep parsing

I currently have a working parser. It parses a file once(not what I want it to do) and then outputs parsed data into a file. I need it to keep parsing and appending to the same output file until the end of the input file. Looks something like this.
try {
// my code parsing the data and appending to eof of output. (works)
}
catch (EOFException eof){
}
Everything is done except the while loop. It only parses once when I need it to keep parsing. I'm looking for a while loop function to reach eof.
I'm also using a DataInputStream. Is there some sort of DataInputStream.hasNext function?
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
i.e. dis.read();
.
//Need a while !eof while loop
try {
// my code parsing the data and appending to eof of output. (works)
}
catch (EOFException eof){
}
Warning: This answer is incorrect. See the comments for explanation.
Instead of looping until an EOFException is thrown, you could take a much cleaner approach, and use available().
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
while (dis.available() > 0) {
// read and use data
}
Alternatively, if you choose to take the EOF approach, you would want to set a boolean upon the exception being caught, and use that boolean in your loop, but I do not recommend it:
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
boolean eof = false;
while (!eof) {
try {
// read and use data
} catch (EOFException e) {
eof = true;
}
}
DataInputStream has a lot of readXXX() methods that do throw EOFException but the method that you're using DataInputStream.read() does not throw EOFException.
To correctly identify the EOF while using read() implement your while loop as follows
int read = 0;
byte[] b = new byte[1024];
while ((read = dis.read(b)) != -1) { // returns numOfBytesRead or -1 at EOF
// parse, or write to output stream as
dos.write(b, 0, read); // (byte[], offset, numOfBytesToWrite)
}
If you are using FileInputStream, here's an EOF method for a class that has a FileInputStream member called fis.
public boolean isEOF()
{
try { return fis.getChannel().position() >= fis.getChannel().size()-1; }
catch (IOException e) { return true; }
}

Categories