Java Socket.readLine() not always reading whole message separated by newLine - java

readLine() works fine in many cases but few times, the line I read in by BufferedReader.readLine() is incomplete line. This question talks about similar issue. However the solutions are not satisfactory. A solution there says that it maybe because of EOF character. But in my case I am not sending any EOF character at all. Below are my codes:
/*Sending Code*/
public void sendToLocalDaemon(String msg){/*msg have no New line or \r*/
localMachineWriter.println(msg);
}
/*Receiving Code*/
public int receiveFromCoordinator(){
String response = "";
while(true){/*Each message separated from new line will have its independent meaning.*/
try{
coordinator.setSoTimeout(1);
try{
response = coordinatorReader.readLine();
}
catch(java.net.SocketTimeoutException e){
response = null;
}
if(response == null){
return coordinatorsMessage.size();
}
coordinatorsMessage.add(response);
}
catch(IOException e){
log(e.getMessage());
//System.exit(0);
}
}
}
/*This is how I set reader and writer*/
public void setReaderWriter() throws IOException{
this.coordinatorWriter = new PrintWriter(coordinator.getOutputStream(),true);
this.coordinatorReader = new BufferedReader(new InputStreamReader(coordinator.getInputStream()));
}
Please either suggest me someway to make this work correctly. Or suggest me some other way by which I can read whole message, with 100% guarantee.

The problem is your read timeout. If it happens, you can lose data. If readLine() times out in the middle of a line, the part read so far is lost. If you set it too short, you will lose a lot of data, and you're setting it much too short. You should set it much higher, or not use one at all.

Related

The String after \n is not being displayed at all in the System output

So, I'm making a simple Server-client program using TCP as part of my college assignment. I've already created one before using UDP and just have to redo it using TCP. However, I came across something funny while coding. Apparently, Strings I'd send out from the server that contains a \n will only display the part of the String before the \n. All the other substring that follows after \n will not be displayed. I'm sort of puzzled by this. Maybe it might have something to do with my code for sending it?
The code below is from the server side.
P.S. I've tried researching a bit about this, and I couldn't really find anything concerning my issue. I've tried using "%n" because I saw it was suggested in a few forums, but that didn't work.
if(clientMessage.equals("1234"))
{
SendMessage(incoming, "Welcome.\nMenu:\n1. Check balance\n2. Deposit\n3. Withdraw\n4. Quit");
}
public static void SendMessage(Socket incoming, String message){
//9. Initialize String to send to client
//BufferedReader output = new BufferedReader(new InputStreamReader(System.in));
String serverMessage;
try {
serverMessage = message;
//10. Initialize PrintStream using getOutputStream() method of
//Socket
PrintStream send = new PrintStream(incoming.getOutputStream());
//11. Use println() method of PrintSteam to send data to client
send.println(serverMessage);
} catch (IOException ex) {
Logger.getLogger(ATMTCPServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
So, in the end I found the mistake I made from a friend of mine who pointed it out. Apparently, the mistake was in the client side. I didn't know that BufferedReader.readLine() would only read one line. So, that was why the substring after \n wasn't displaying. Afterwards, I came across a few other problems, but with the help of my friend, I eventually solved the problems and finished my assignment. Thank you to everyone who gave their comments!
P.S. I'll post the code of what I did to solve the problem below. The code below is from the client side. I didn't have to change anything on the server side.
serverMessage = incoming.readLine();
String[] messages = serverMessage.split("----");
for(int i = 0; i < messages.length; i++){
if(choice.equals("2") || choice.equals("3"))
{
System.out.print(messages[i]);
}
else
{
System.out.println(messages[i]);
}
}

Separating Get request Response body in java Socket programming

I'm trying to write a curl like program using java, which uses only java socket programming (and not apache http client or any other APIs)
I want to have the option of showing whole or only the body of the response to my get request to user. Currently came up with the following code:
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String t;
while ((t = br.readLine()) != null) {
if (t.isEmpty() && !parameters.isVerbose()) {
StringBuilder responseData = new StringBuilder();
while ((t = br.readLine()) != null) {
responseData.append(t).append("\r\n");
}
System.out.println(responseData.toString());
parameters.verbose = false;
break;
} else if(parameters.isVerbose())// handle output
System.out.println(t);
}
br.close();
When the verbose option is on, it works quick and shows the whole response body in less than a second. but when I want to just have the body of the message it takes too much time(approx 10 sec) to hand it out.
Does any one knows how can it be processed in a faster way?
Thank you.
I'm going to assume what you mean by slow is that it starts displaying something almost immediately but keeps on printing lines for a long time. Writing to the console takes time, and you're printing each line invidually while in the other code path you first store the entire response in memory and then flush it to the console.
If the verbose response is small enough to fit in memory, you should do the same, otherwise you can decide on an arbitrary number of lines to print in batches (i.e; you accumulate n lines in memory and then flush to the console, clear the StringBuilderand repeat).
The most elegant way to implement my suggestion is to use a PrintStream wrapping a BufferedOutputStream, itself wrapping System.out. All my comments and advices are condensed in the following snippet:
private static final int BUFFER_SIZE = 4096;
public static void printResponse(Socket socket, Parameters parameters) throws IOException {
try (BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream printStream = new PrintStream(new BufferedOutputStream(System.out, BUFFER_SIZE))) {
// there is no functional difference in your code between the verbose and non-verbose code paths
// (they have the same output). That's a bug, but I'm not fixing it in my snippet as I don't know
// what you intended to do.
br.lines().forEach(line -> printStream.append(line).append("\r\n"));
}
}
If it uses any language construct you don't know about, feel free to ask further questions.

Strange behavior of EOFException

I have some simple class that is DataInputStream stream to read from file.
I have surrounded this stream with EOFException try-catch block.
It has some strange behavior coz sometimes it throws EOFException into text that is read.
Output to console:
"The vessel was in as good condition as I am, and as, I hope
you ar#End of streame#, M. Morrel, and this day and a half was lost from
pure whim, for the pleasure of going ashore, and nothing
else."
I couldn't figure out what is cause of this strange behavior...
Here is code snippet:
public class FormattedMemoryInput {
public static void main(String[] args) throws IOException {
boolean done = false;
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(
BufferedInputFile.read("./gutenberg/cristo.txt").getBytes()));) {
while (!done) {
System.out.print((char) in.readByte());
}
} catch (EOFException e) {
System.err.println("#End of stream#");
}
}
}
It uses static method BufferedInputFile.read() to read first 500 lines:
public class BufferedInputFile {
// Throw exceptions to console:
public static String read(String filename) throws IOException {
// Reading input by lines:
BufferedReader in = new BufferedReader(new FileReader(filename));
StringBuilder sb = new StringBuilder();
String s;
int i = 0;
while ((s = in.readLine()) != null && (i < 500)) {
sb.append(s + "\n");
i++;
}
in.close();
return sb.toString();
}
Why EOFException is thrown into text?
Solution:
It was at adding one line:
while (!done) {
System.out.print((char) in.readByte());
System.out.flush(); // this one
}
Well, you're getting an EOFException because you're reading forever - you never change the value of done.
The reason it's appearing in the middle of the text instead of at the end is that you're using System.err to print in the exceptional case, and System.out to print the main text. Those are separate streams, flushed separately. If you flush System.out before writing to System.err, I suspect you'll see the main text before the error message. (Note that you're using println on System.err, which will flush automatically, but just print on System.out, which won't.)
There are various other things I'd change about the code - particularly the use of String.getBytes() without specifying an encoding - but assuming I've understood your question correctly, the difference in streams is the reason you're looking for.
System.out is buffered by default; System.err isn't. If you redirect one of the output streams, either in your program or from the shell, you should see the output in the expected order. You can force System.out to print its output by calling System.out.flush();; try inserting that at the end of your while loop.

Java: Getting multiple lines from socket

I have a Java application that consists of a client and a server. The client sends encrypted commands to the server, and the server executes them.
The problem that I am having right now is that, with my encryption algorithm, sometimes the encrypted command contains "\n" or "\r" characters, which mess up my server code. This is because I am using the readLine() method, which stops when it finds a line terminator. What I need is a way to read all the characters the client sends into one string.
Here is my code:
public void run(){
System.out.println("Accepted Client!");
try{
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "ISO8859_1"));
out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "ISO8859_1"));
String clientCommand = null;
while(RunThread){
// read incoming stream
do{
clientCommand = in.readLine();
}while(clientCommand == null);
//decrypt the data
System.out.println("Client: " + clientCommand);
if(clientCommand.equalsIgnoreCase("quit")){
RunThread = false;
}else{
//do something
out.flush();
}
}
}catch(Exception e){
e.printStackTrace();
}
}
Everything I've tried (various forms of nested loops using the read() function) hasn't worked. I would welcome any help or suggestions. Thanks, everyone!
I don't see encryption in the code you posted, but usually it's not a good idea to rely on separator characters.
When sending binary data, you should prepend the length of the data to the stream, and then you know exactly how many bytes to expect (and when the message will end.) It's more efficient to do things that way too instead of looking for a newline character.
// read incoming stream
do{
clientCommand = in.readLine();
}while(clientCommand == null);
That == null seems wrong
Try
String line = null;
do {
line = in.readLine ();
clientCommand += line
} while (line != null);
One thing you must do, when working with TCP/IP, is to send the message length before the actual message. The application level cannot foresee the package size the TCP level is delivering to the destiny. So, before your message, you have to send a header with the message size and the destiny would read just these bytes.
About readLine(), I think it's better use another approaches like streams. Shortly, one suggestion:
Socket oSocket = new Socket(sAddress, iPort);
PrintWriter out = new PrintWriter(oSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(oSocket.getInputStream()));
do{
clientCommand = in.readLine();
} while(clientCommand == null);
This makes no sense. readLine() only returns null at end of stream, so you are telling Java to loop infinitely at end of stream. I don't even understand why there is a loop at all. You don't want to ignore any input from the client, you want to process it all. You should read one line from the client, execute it, and read another line. Repeat until null, then close the socket.

Java: Pause thread and get position in file

I'm writing an application in Java with multithreading which I want to pause and resume.
The thread is reading a file line by line while finding matching lines to a pattern. It has to continue on the place I paused the thread. To read the file I use a BufferedReader in combination with an InputStreamReader and FileInputStream.
fip = new FileInputStream(new File(*file*));
fileBuffer = new BufferedReader(new InputStreamReader(fip));
I use this FileInputStream because I need the filepointer for the position in the file.
When processing the lines it writes the matching lines to a MySQL database. To use a MySQL-connection between the threads I use a ConnectionPool to make sure just one thread is using one connection.
The problem is when I pause the threads and resume them, a few matching lines just disappear. I also tried to subtract the buffersize from the offset but it still has the same problem.
What is a decent way to solve this problem or what am I doing wrong?
Some more details:
The loop
// Regex engine
RunAutomaton ra = new RunAutomaton(this.conf.getAuto(), true);
lw = new LogWriter();
while((line=fileBuffer.readLine()) != null) {
if(line.length()>0) {
if(ra.run(line)) {
// Write to LogWriter
lw.write(line, this.file.getName());
lw.execute();
}
}
}
// Loop when paused.
while(pause) { }
}
Calculating place in file
// Get the position in the file
public long getFilePosition() throws IOException {
long position = fip.getChannel().position() - bufferSize + fileBuffer.getNextChar();
return position;
}
Putting it into the database
// Get the connector
ConnectionPoolManager cpl = ConnectionPoolManager.getManager();
Connector con = null;
while(con == null)
con = cpl.getConnectionFromPool();
// Insert the query
con.executeUpdate(this.sql.toString());
cpl.returnConnectionToPool(con);
Here's an example of what I believe you're looking for. You didn't show much of your implementation so it's hard to debug what might be causing gaps for you. Note that the position of the FileInputStream is going to be a multiple of 8192 because the BufferedReader is using a buffer of that size. If you want to use multiple threads to read the same file you might find this answer helpful.
public class ReaderThread extends Thread {
private final FileInputStream fip;
private final BufferedReader fileBuffer;
private volatile boolean paused;
public ReaderThread(File file) throws FileNotFoundException {
fip = new FileInputStream(file);
fileBuffer = new BufferedReader(new InputStreamReader(fip));
}
public void setPaused(boolean paused) {
this.paused = paused;
}
public long getFilePos() throws IOException {
return fip.getChannel().position();
}
public void run() {
try {
String line;
while ((line = fileBuffer.readLine()) != null) {
// process your line here
System.out.println(line);
while (paused) {
sleep(10);
}
}
} catch (IOException e) {
// handle I/O errors
} catch (InterruptedException e) {
// handle interrupt
}
}
}
I think the root of the problem is that you shouldn't be subtracting bufferSize. Rather you should be subtracting the number of unread characters in the buffer. And I don't think there's a way to get this.
The easiest solution I can think of is to create a custom subclass of FilterReader that keeps track of the number of characters read. Then stack the streams as follows:
FileReader
< BufferedReader
< custom filter reader
< BufferedReader(sz == 1)
The final BufferedReader is there so that you can use readLine ... but you need to set the buffer size to 1 so that the character count from your filter matches the position that the application has reached.
Alternatively, you could implement your own readLine() method in the custom filter reader.
After a few days searching I found out that indeed subtracting the buffersize and adding the position in the buffer wasn't the right way to do it. The position was never right and I was always missing some lines.
When searching a new way to do my job I didn't count the number of characters because it are just too many characters to count which will decrease my performance a lot. But I've found something else. Software engineer Mark S. Kolich created a class JumpToLine which uses the Apache IO library to jump to a given line. It can also provide the last line it has readed so this is really what I need.
There are some examples on his homepage for those interested.

Categories