Reputation: 15
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;
}
}
Upvotes: 0
Views: 383
Reputation: 654
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;
}
}
Upvotes: 1