Return BufferedReader - java

I ran into a problem which I don't have any idea what could be happening.
I have a class which calls a second class to send a command throught ssh and return the result.
The result is a BufferedReader, and then this result is treated in my first class.
First class:
.
.
.
String command = "ping " + ip + " -c 1";
BufferedReader result = instance.sendCommand(command);
// close only after all commands are sent
System.out.println("out of sshManager result : "+result);
System.out.println("out of sshManager line : "+result.readLine());
String line = null;
while ((line = result.readLine()) != null) {
System.out.println("out of sshManager line: "+line);
}
Second class:
public BufferedReader sendCommand(String command) throws JSchException, IOException {
//StringBuilder outputBuffer = new StringBuilder();
Channel channel = sesConnection.openChannel("exec");
((ChannelExec) channel).setCommand(command);
channel.connect();
InputStream commandOutput = channel.getInputStream();
System.out.println("This is in sshmanager SSHManager: " + commandOutput);
result = new BufferedReader(new InputStreamReader(commandOutput));
String line = null;
System.out.println(" sshmanager result : " + result());
System.out.println(" sshmanager result line : " + result.readLine());
while ((line = result.readLine()) != null) {
System.out.println("in sshmanager: " + line);
}
System.out.println("in sshmanager result : " + result);
channel.disconnect();
return result;
}
Result:
This is in sshmanager SSHManager: com.jcraft.jsch.Channel$MyPipedInputStream#40d5bd18
sshmanager result : java.io.BufferedReader#10a5ae6e
sshmanager result line : PING 192.168.11.11 (192.168.11.11) 56(84) bytes of data.
in sshmanager: From 192.168.11.77 icmp_seq=1 Destination Host Unreachable
in sshmanager:
in sshmanager: --- 192.168.11.11 ping statistics ---
in sshmanager: 1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 3006ms
in sshmanager:
in sshmanager result: java.io.BufferedReader#10a5ae6e
out of sshManager result: java.io.BufferedReader#10a5ae6e
out of sshManager line: null
The objects is well created in my second class but I don't know why, when I try to manage the object in my first class the content is null.
Do you have any idea what is worng?

The BufferedReader has already read through the file when it is returned to the first method. You may want to return a List<String> containing the contents of the file instead of the BufferedReader.
public List<String> sendCommand(String command) throws JSchException, IOException {
List<String> lines = new LinkedList<String>();
Channel channel = sesConnection.openChannel("exec");
((ChannelExec) channel).setCommand(command);
channel.connect();
InputStream commandOutput = channel.getInputStream();
result = new BufferedReader(new InputStreamReader(commandOutput));
String line = null;
while ((line = result.readLine()) != null) {
lines.add(line);
}
channel.disconnect();
return lines;
}

It's all coming from the concept of streaming.
Once you advance through the stream in the "second class", you actually consume the stream. So, at the moment when you return it to the "first class", the stream is entirely consumed. Therefore, you cannot stream anything anymore.
Please note, that even if you wrap the stream into a reader, the read operations (e.g. readLine) are forwarded to the stream.

A bufferred reader is like a string of bytes that you can read from once.
Your basic problem is that inside the function you've already extracted the text from the reader, so when you try again you just get null (because the reader is NOW empty).

Related

Datainputstream and readUTF have data lost

I'm using java and received some json string from a server. I received json strings with readUTF but there is some data lost. I didn't received first two character of the every json packet.
Another problem is there is delay to received json strings. For example server sent one json string and client could not received it until approximately 50 json strings sent by server and client shows all the json strings suddenly.
What is the main problems?
public void run() {
System.out.println("hi from thread" + id);
try {
clientSocket = new Socket("192.168.1.22", id);
output = new PrintStream(clientSocket.getOutputStream());
input = new DataInputStream(clientSocket.getInputStream());
inputLine = new DataInputStream(new BufferedInputStream(System.in));
}
catch( IOException e){
System.out.println(e);
}
String responseLine;
try{
while(true){
output.println( id + " ");
System.out.println("sent:" + id + " ");
responseLine = input.readUTF();
System.out.println("received: " + responseLine);
}
}
catch (IOException e) {
System.out.println(e);
}
}
Because of server send data with UTF format, so I cannot receive them with Bufferedreader
I've had this problem before with applications like this, the main cause is DataInputStream which expects input to be in a certain format which I assume is not being conformed to by the server, try using BufferedReader instead as so:
BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
Then whenever you wish to read data just use
some_string_here = input.readLine();
Note this requires each data value sent to end with a end line character "\n" or "\r".

The DataOutputStream text from Server to Client is indented weird and produces a 4

Right now, I'm trying to make a server that can display messages to the client when they connect (through localhost). When I connect through telnet, it gives me weird indentation. The code for the server is:
private ServerSocket middleman;
private int port = 8080;
private Socket client;
protected void createSocketServer()
{
try
{
while (true){
middleman = new ServerSocket(port);
client = middleman.accept();
middleman.close();
PrintWriter out = new PrintWriter(client.getOutputStream(),true);
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String line;
//Client stuff
DataOutputStream dOut = new DataOutputStream(client.getOutputStream());
while((line = in.readLine()) != null)
{
System.out.println("echo: " + line);
dOut.writeByte(1);
dOut.writeUTF("Good day to you user. Here is a selection of poems " + "\n");
dOut.writeUTF("1. Cupcake Poem" + "\n");
dOut.flush();
//Response
if(line.equals("cupcake")){
try{
FileReader fileReader = new FileReader(poem);
BufferedReader bufferedReader = new BufferedReader(fileReader);
StringBuffer stringBuffer = new StringBuffer();
String poemLine;
while((poemLine = bufferedReader.readLine()) != null){
stringBuffer.append(poemLine);
stringBuffer.append("\n");
}
fileReader.close();
System.out.println("Contents of file:");
//System.out.println(stringBuffer.toString());
dOut.writeUTF(stringBuffer.toString());
dOut.flush();
} catch(IOException e){
e.printStackTrace();
}
}
else{
System.out.println("wrong!, the line is:" + line);
}
}
}
}
catch(IOException e)
{
System.out.println(e);
}
}
On the client side, I'll open the command prompt and type telnet localhost 8080 then I'll type something like "fish". It will print
[?]Good day to you user. here is a selection of poems
1. Cupcake Poem
Why does it do this? If I type "cupcake" on client, it will read the file, but have weird spacing. Is this something to do with Telnet?
For telnet the correct end-of-line sequence is "\r\n". Newline by itself will only go down to the next line, but it will not back up to the first column, which what the carriage-return does.
Also note that the order matters, the telnet specifications says that it has to be "\r\n", in that order.
Also, you don't have to append the output with the newline-sequence like you do. You can write it all as a single string:
dOut.writeUTF("1. Cupcake Poem\r\n");

Writing a simple HTTP server to accept GET requests

I'm trying to create a simple server that accepts a request, and then writes the content of a file to the browser that sent the request. The server connects and writes to the socket. However my browser says
no data received
and doesn't display anything.
public class Main {
/**
* #param args
*/
public static void main(String[] args) throws IOException{
while(true){
ServerSocket serverSock = new ServerSocket(6789);
Socket sock = serverSock.accept();
System.out.println("connected");
InputStream sis = sock.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(sis));
String request = br.readLine(); // Now you get GET index.html HTTP/1.1`
String[] requestParam = request.split(" ");
String path = requestParam[1];
System.out.println(path);
PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
File file = new File(path);
BufferedReader bfr = null;
String s = "Hi";
if (!file.exists() || !file.isFile()) {
System.out.println("writing not found...");
out.write("HTTP/1.0 200 OK\r\n");
out.write(new Date() + "\r\n");
out.write("Content-Type: text/html");
out.write("Content length: " + s.length() + "\r\n");
out.write(s);
}else{
FileReader fr = new FileReader(file);
bfr = new BufferedReader(fr);
String line;
while ((line = bfr.readLine()) != null) {
out.write(line);
}
}
if(bfr != null){
bfr.close();
}
br.close();
out.close();
serverSock.close();
}
}
}
Your code works for me (data shows up in the browser), if I use
http://localhost:6789/etc/hosts
and there is a file /etc/hosts (Linux filesystem notation).
If the file does not exist, this snippet
out.write("HTTP/1.0 200 OK\r\n");
out.write(new Date() + "\r\n");
out.write("Content-Type: text/html\r\n");
out.write("\r\n");
out.write("File " + file + " not found\r\n");
out.flush();
will return data that shows up in the browser: Note that I have explicitly added a call to flush() here. Make sure that out is flushed in the other case as well.
The other possibility is to reorder your close statements.
A quote from EJP's answer on How to close a socket:
You should close the outermost output stream you have created from the socket. That will flush it.
This is especially the case if the outermost output stream is (another quote from the same source):
a buffered output stream, or a stream wrapped around one. If you don't close that, it won't be flushed.
So out.close() should be called before br.close().

How to send EOF to a process in Java?

I want to run groff in a Java program. The input comes from a string. In real command line, we will terminate the input by ^D in Linux/Mac. So how to send this terminator in Java program?
String usage +=
".Dd \\[year]\n"+
".Dt test 1\n"+
".Os\n"+
".Sh test\n"+
"^D\n"; // <--- EOF here?
Process groff = Runtime.getRuntime().exec("groff -mandoc -T ascii -");
groff.getOutputStream().write(usage.getBytes());
byte[] buffer = new byte[1024];
groff.getInputStream().read(buffer);
String s = new String(buffer);
System.out.println(s);
Or any other idea?
^D isn't a character; it's a command interpreted by your shell telling it to close the stream to the process (thus the process receives EOF on stdin).
You need to do the same in your code; flush and close the OutputStream:
String usage =
".Dd \\[year]\n" +
".Dt test 1\n" +
".Os\n" +
".Sh test\n";
...
OutputStream out = groff.getOutputStream();
out.write(usage.getBytes());
out.close();
...
I wrote this utility method:
public static String pipe(String str, String command2) throws IOException, InterruptedException {
Process p2 = Runtime.getRuntime().exec(command2);
OutputStream out = p2.getOutputStream();
out.write(str.getBytes());
out.close();
p2.waitFor();
BufferedReader reader
= new BufferedReader(new InputStreamReader(p2.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
return sb.toString();
}

BufferedReader readLine() blocks

When receiving data using readLine(), even though I put a "\n" at the end of the message
using the .flush when sending the message, the while loop that reads my message still blocks.
Only when closing the socket connection, it leaves the loop.
Here's the client code :
bos = new BufferedOutputStream(socket.
getOutputStream());
bis = new BufferedInputStream(socket.
getInputStream());
osw = new OutputStreamWriter(bos, "UTF-8");
osw.write(REG_CMD + "\n");
osw.flush();
isr = new InputStreamReader(bis, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String response = "";
String line;
while((line = br.readLine()) != null){
response += line;
}
and the server's code:
BufferedInputStream is;
BufferedOutputStream os;
is = new BufferedInputStream(connection.getInputStream());
os = new BufferedOutputStream(connection.getOutputStream());
isr = new InputStreamReader(is);
String query= "";
String line;
while((line = br.readLine()) != null){
query+= line;
}
String response = executeMyQuery(query);
osw = new OutputStreamWriter(os, "UTF-8");
osw.write(returnCode + "\n");
osw.flush();
My code blocks at the server while loop.
Thanks.
The BufferedReader will keep on reading the input until it reaches the end (end of file or stream or source etc). In this case, the 'end' is the closing of the socket. So as long as the Socket connection is open, your loop will run, and the BufferedReader will just wait for more input, looping each time a '\n' is reached.
I tried a lot of solutions but the only one not blocking the execution was the following:
BufferedReader inStream = new BufferedReader(new InputStreamReader(yourInputStream));
String line;
while(inStream.ready() && (line = inStream.readLine()) != null) {
System.out.println(line);
}
The inStream.ready() returns false if the next readLine() call will block the execution.
This is because of the condition in the while-loop: while((line = br.readLine()) != null)
you read a line on every iteration and leve the loop if readLine returns null.
readLine returns only null, if eof is reached (= socked is closed) and returns a String if a '\n' is read.
if you want to exit the loop on readLine, you can omit the whole while-loop und just do:
line = br.readLine()
This happens because the InputStream is not ready to be red, so it blocks on in.readLine() .
Please try this :
boolean exitCondition= false;
while(!exitCondition){
if(in.ready()){
if((line=in.readLine())!=null){
// do whatever you like with the line
}
}
}
Of course you have to control the exitCondition .
An other option can be the use of nio package, which allows asynchronised (not blocking) reading but it depend on your need.
It'd be better avoid using readline(). This method is dangerous for network communications because some servers don't return LF/CR symbols and your code will be stuck. When you read from a file it isn't critical because you will reach end of the file anyway and stream will be closed.
public String readResponse(InputStream inStreamFromServer, int timeout) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(inStreamFromServer, Charsets.UTF_8));
char[] buffer = new char[8092];
boolean timeoutNotExceeded;
StringBuilder result = new StringBuilder();
final long startTime = System.nanoTime();
while ((timeoutNotExceeded = (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) < timeout))) {
if (reader.ready()) {
int charsRead = reader.read(buffer);
if (charsRead == -1) {
break;
}
result.append(buffer, 0, charsRead);
} else {
try {
Thread.sleep(timeout / 200);
} catch (InterruptedException ex) {
LOG.error("InterruptedException ex=", ex);
}
}
}
if (!timeoutNotExceeded) throw new SocketTimeoutException("Command timeout limit was exceeded: " + timeout);
return result.toString();
}
It has a timeout and you can interrupt communication if it take a lot of time
if you want to get what's in the socket without being forced to close it simply use ObjectInputStream and ObjectOutputStream ..
Example:
ObjectInputStream ois;
ObjectOutputStream oos;
ois = new ObjectInputStream(connection.getInputStream());
String dataIn = ois.readUTF(); //or dataIn = (String)ois.readObject();
oos = new ObjectOutputStream(connection.getOutputStream());
oos.writeUtf("some message"); //or use oos.writeObject("some message");
oos.flush();
.....
readline() and read() will be blocked while socket doesn't close. So you should close socket:
Socket.shutdownInput();//after reader
Socket.shutdownOutput();//after wirite
rather than Socket.close();

Categories

Resources