how to properly close ssh connection / session here? - java

I have a client/server socket program.
Server part is connecting via ssh to a host, runs a script, and sends each line of the output to the client.
The below server code part returns a BufferedReader containing the script output as it happens:
public synchronized BufferedReader runScript(<params>) {
BufferedReader br = null ;
try {
Connection conn = new Connection(host);
conn.connect();
... // authentication part
Session sess = conn.openSession();
sess.execCommand("ascript");
InputStream stdout = new StreamGobbler(sess.getStdout());
br = new BufferedReader(new InputStreamReader(stdout));
} catch (Exception e) {
e.printStackTrace();
}
return br;
}
The above method is called from another server-side class/code as below, writing each line of the BufferedReader to the client through a socket, so that client sees the live output of the script as it runs :
BufferedReader br = new UnixCommandExecutor().runScript(<params>);
String line;
while ((line = br.readLine()) != null) {
out.writeObject(line);
}
The obvious problem with runScript method is that it doesn't close the ssh Connection & Session (ganymed ssh lib), as it instantly returns the BufferedReader (if I'm not mistaken) while the underlying script still runs . If I close these before the return statement, the BufferedReader would be incomplete.
So how do I properly close connection/session here as soon as the underlying script completes ?
(I'm aware of try-with-resources and will use it, however I doubt it will solve the problem completely?)

I would suggest that you refactor the code, so that you
either wrap the parts into an object and handling the close operation later
or you consume the Reader immediately and close the connection after you are done with it.
Do not pass the Reader to the outside without maintaining the connection.
Below a somewhat simplified example on how it could be done.
If you need to process through mutliple steps before your are done with the Reader, you might not be able to wrap the ResultHandler in a try { ... } catch block. In that case you need a different meachnism to ensure that this will eventually be closed.
But judging from your problem description that might not be the case.
If you do not want to block till the operation is done (anyway this operation is something that should be executed in a background thread), then you probably want to send each output line you receive to somewhere where it can be displayed. In this case you can should provide an interface that you use to forward the received lines.
While the reader still receives output (as long as the input stream / connection is active) you`ll probably need to loop. Somehow you need to figure out when your operation is completed.
For example your script could close the connection (from the serverside) once it is done or return something specific to you that you can interpret as end of operations.
public class ResultHandler {
String host;
Connection conn;
BufferedReader reader = null;
public ResultReader(String host) {
this.host = host;
}
public void connect(<params>) throws Exception {
// if you intend to reuse the object, just check that it was properly cleanedup before
close();
conn = new Connection(host);
conn.connect();
... // authentication part
// you might want to move the actual handling to a different method
Session sess = conn.openSession();
sess.execCommand("ascript");
InputStream stdout = new StreamGobbler(sess.getStdout());
br = new BufferedReader(new InputStreamReader(stdout));
}
public BufferedReader getReader() {
return this.reader;
}
public void close() {
If (reader != null) {
reader.close();
}
if (conn != null) {
conn.close();
}
}
public void finalize() {
close();
}
}
synchronized void runScript(<params>) {
ResultHandler handler;
try {
handler = new ResultHandler(host);
handler.connect();
// consume the reader for whatever you need to do
} catch (Exception e) {
e.printStackTrace();
} finally {
// or use try-with-resource and implement the proper interface for that
if (handler != null) {
handler.close();
}
}
}

Related

Able to write the data successfully but not able to read the data from the server

I have two classes server and client. I am running both the server and the client on the intelliji. I am able to write the data to the Json file on the server but when it comes to reading the data, I am not able to read it. My application is not responding when I am trying to read the data. I am new to Socket Programming please help me.
Here is the code on the client side
import java.io.*;
import java.net.Socket;
public class Client {
public String readDataFromServer(Socket socket) throws IOException {
InputStreamReader inputStreamReader = new
InputStreamReader(socket.getInputStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
return bufferedReader.readLine();
}
public void writeDataToServer(String obj) throws IOException {
Socket socket = new Socket("localhost", 1299);
OutputStreamWriter outputStreamWriter = new
OutputStreamWriter(socket.getOutputStream());
PrintWriter printWriter = new PrintWriter(outputStreamWriter);
printWriter.write(obj);
printWriter.flush();
printWriter.close();
}
}
Here is the code on the server side
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
static void writeJson (String str) throws IOException {
FileWriter pw = null;
try {
pw = new FileWriter("MYJSON.json", true);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
pw.write(str + '\n');
pw.flush();
try {
} catch (Exception E) {
E.printStackTrace();
}
pw.close();
}
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(1299);
Socket socket = serverSocket.accept();
InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = bufferedReader.readLine();
writeJson(str);
FileReader fileReader = new FileReader("MYJSON.json");
BufferedReader buff = new BufferedReader(fileReader);
OutputStreamWriter outputStreamWriter = new
OutputStreamWriter(socket.getOutputStream());
PrintWriter printWriter = new PrintWriter(outputStreamWriter);
printWriter.write(buff.readLine());
printWriter.flush();
}
}
I have another class called display controller which is calling the method which is calling the method by passing the socket object. Here is the piece of code from this class.
Client client = new Client();
button1.setOnAction(e-> {
try {
String str;
while ((str = client.readDataFromServer(socket)) != null) {
Object obj = null;
try {
obj = jsonParser.parse(str);
What I am doing wrong here? How do I fix it?
Thank you
There's a couple of issues in your code.
The main one is in the main method of the Server class. Your server only accepts one connection. That connection writes and reads the json file and then your main method ends. If your main program ends, then the server is gone. This means that the first client that connects will work and write to the file, but any subsequent connections will not connect because there's no server accepting connections anymore. Typical servers run indefinitely by using a while loop with true as the condition.
Example Structure of a server without threads:
public class Server {
// this class represents an instance of a client connection to this server
// It's an object that keeps track of the socket created by referencing
// the connection.
private class ClientInstanceOnTheServer {
private Socket connectionToClient;
public ClientInstanceOnTheServer(Socket connectionToClient) {
this.connectionToClient = connectionToClient;
}
private void logicToServeAClient() {
// here goes the logic that serves a client
}
public void run () {
try {
logicToServeAClient();
} finally {
try {
socket.close();
} catch (IOException e) {// handle exceptions!}
}
}
}
public static void main(String [] args) {
try {
ServerSocket serverSocket = new ServerSocket(1299);
while (true) { // run indefinitely
Socket socket = serverSocket.accept(); // accept connections from clients
// keep track of the socket object as it represents a connection to a client
// the server is responsible for keeping track of its connections to clients
// Example:
ClientInstanceOnTheServer client = new ClientInstanceOnTheServer(socket);
client.run();
}
} finally {
serverSocket.close();
}
}
}
Example Structure of a server with Threads:
NOTE: The code below is not to represent a complete solution with threads, but rather an example to explain how a server works.
public class Server {
// this class represents an instance of a client connection to this server
// It's an object that keeps track of the socket created by
// the connection and it runs in a separate thread to not block
// the main method thread on this server.
private class ClientInstanceOnTheServer extends Thread {
private Socket connectionToClient;
public ClientInstanceOnTheServer(Socket connectionToClient) {
this.connectionToClient = connectionToClient;
}
private void logicToServeAClient() {
// here goes the logic that serves a client
}
public void run () {
try {
logicToServeAClient();
} finally {
try {
socket.close();
} catch (IOException e) {// handle exceptions!}
}
}
}
public static void main(String [] args) {
try {
ServerSocket serverSocket = new ServerSocket(1299);
while (true) { // run indefinitely
Socket socket = serverSocket.accept(); // accept connections from clients
// keep track of the socket object as it represents a connection to a client
// the server is responsible for keeping track of its connections to clients
// and it should use a separate thread for each client to not block the main method thread.
// Example:
ClientInstanceOnTheServer client = new ClientInstanceOnTheServer(socket);
client.start(); // this will execute the run method in ClientInstanceOnTheServer class.
}
} finally {
serverSocket.close();
}
}
}
Your server is always doing both, writing and reading the json file, regardless of what the client wants. The server should somehow allow the client to communicate what it wants to do, and then it executes only what the client asked for. If we use the skeleton code above, this logic would go in the method logicToServeAClient of the ClientInstanceOnTheServer class. The server and client use the socket object's input and output streams to communicate with each other. The server and client need to agree beforehand on which commands/operations the client needs and the server is willing to serve. In your case, it would be READ and WRITE. Then you create a contract (Protocol) between the client and server on how to send these commands to the server and how the server will respond to the client for each command.
Example of a protocol:
// client sends READ to server
// client waits for respond from server
// server read json file and send it to the client
// client sends WRITE to server
// server then waits for the client to send the string to write.
// Once it receives the string, it writes it to the json file.
All of this is achievable using the socket's input and output streams
It's important to distinguish the difference between the Client and the ClientInstanceOnTheServer classes. Client is your Client class that connects to the server and ClientInstanceOnTheServer holds the connection and also runs the server code that serves the commands requested by the Client class. In the protocol above, whenever client is mentioned, is referring to the Client class. Whenever the server is mentioned is referring to the ClientInstanceOnTheServer class.
You can find more examples on google, like: http://cs.lmu.edu/~ray/notes/javanetexamples/. However, this should set you up on a path to fix your issue.
Cheers

How to make http call from standalone java application

I'm making a small dictionary kind of app using java swings. I'm using oxford dictionary api for that. Is there any way to make a simple ajax request in java without using servelets and all advanced java concepts. As in android we use http url connection to do this job.I googled a lot for finding this but I could't find a solution as every page is showing results using servelets. But I know core java alone.If it is possible to make ajax call without servelts please help me...Thanks in advance...
Use HttpURLConnection class to make http call.
If you need more help for that then go for offical documentation site of java Here
Example
public class JavaHttpUrlConnectionReader {
public static void main(String[] args) throws IOException{
String results = doHttpUrlConnectionAction("https://your.url.com/", "GET");
System.out.println(results);
}
public static String doHttpUrlConnectionAction(String desiredUrl, String requestType) throws IOException {
BufferedReader reader = null;
StringBuilder stringBuilder;
try {
HttpURLConnection connection = (HttpURLConnection) new URL(desiredUrl).openConnection();
connection.setRequestMethod(requestType);// Can be "GET","POST","DELETE",etc
connection.setReadTimeout(3 * 1000);
connection.connect();// Make call
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));// Reading Responce
stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
return stringBuilder.toString();
} catch (IOException e) {
throw new IOException("Problam in connection : ", e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ioe) {
throw new IOException("Problam in closing reader : ", ioe);
}
}
}
}
}
It will make a call and give response as return string. If you want to make POST call the need to do some extra for that :
try{
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.write(postParam.getBytes());
} catch(IOException e){
}
Note : Here postParam is String type with value somthing like "someId=156422&someAnotherId=32651"
And put this porson befor connection.connect() statement.

Java ObjectOutputStream's Method flush()

I am currently learning networking, specifically client-server classes.
I have done much research and implemented various test programs but I can't figure out why/when one would need to use the flush() method.
How can there be data mistakenly left in the output stream if it is always read in by the input stream? As dictated by the client-server code.
I tried to test my basic echo client server program by omitting the flush() but I could not break it.
When testing the flush() by writing twice from the client side and only reading once for the server's reply all that happened was a backlog (I assume the stream acts like a queue?) in the server's replies.
Then I took the same code and added flush() before and after the second write and it made no difference. It's as if the flush() doesn't actually clear the stream.
So can someone please explain in what scenario with regards to client/server stream interactions would flush() be required?
Server:
public class ServerApp
{
private ServerSocket listener;
private Socket clientCon;
public ServerApp()
{
try
{
listener = new ServerSocket(1234, 10);
} catch (IOException e)
{
e.printStackTrace();
}
}
public void listen()
{
try
{
System.out.println("Server is listening!");
clientCon = listener.accept();
System.out.println("Server: Connection made with Client");
processClient();
} catch (IOException e)
{
e.printStackTrace();
}
}
public void processClient()
{
try(ObjectOutputStream out = new ObjectOutputStream(clientCon.getOutputStream()); ObjectInputStream in = new ObjectInputStream(clientCon.getInputStream()))
{
String msg;
while(!(msg = (String)in.readObject()).equalsIgnoreCase("Shutdown"))
{
out.writeObject("Server: " + msg);
out.flush();
}
out.writeObject("Server is powering down...");
out.close();
in.close();
} catch (IOException | ClassNotFoundException e)
{
e.printStackTrace();
}
}
public static void main (String args[])
{
ServerApp sa = new ServerApp();
sa.listen();
}
}
Client:
public class ClientApp
{
private Socket serverCon;
public ClientApp()
{
try
{
serverCon = new Socket("127.0.0.1", 1234);
} catch (IOException e)
{
e.printStackTrace();
}
}
public void communicate()
{
try (ObjectOutputStream out = new ObjectOutputStream(serverCon.getOutputStream()); ObjectInputStream in = new ObjectInputStream(serverCon.getInputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)))
{
String response = null;
do
{
System.out.println("Enter your message for server: ");
out.writeObject(br.readLine());
out.flush();
out.writeObject("Flush not working");
out.flush();
response = (String) in.readObject();
System.out.println(response);
response = (String) in.readObject();
System.out.println(response);
} while (!response.equalsIgnoreCase("Server is powering down..."));
} catch (IOException | ClassNotFoundException e)
{
e.printStackTrace();
}
}
public static void main(String args[])
{
ClientApp ca = new ClientApp();
ca.communicate();
}
}
The method flush() is used to flush out any internal buffers that may be in use. For example using a BufferedOutputStream the contents are written in chunks to improve performance (it's slower to write each byte as they come).
Depending on usage, you might never have to call flush(). However let's say you send a small String (converted to byte[]) and it fits nicely in the internal buffer. The contents of the buffer won't be sent until the buffer is full or flush() is called.
Now let's say you're writing over the network, and you expect the other side to answer something to your small String. Since it's still in the buffer, the other side won't receive it and it can result in both sides waiting forever.
Object streams are another beast, and I'm a little disappointed that so many beginners are using them. There should be a warning in the class saying "Objects may be more difficult to send/receive than they appear".
ObjectOutputStream delegates the flush() call to its internal BlockDataOutputStream which has 3 buffers sized 1024, 5 and 256 for "blockdata", header data and characters respectively.
Try it with new ObjectOutputStream(new BufferedOutputStream(clientCon.getOutputStream())) and you'll see a difference with and without flush(). It causes flushing of the underlying buffered output stream. Without a buffered stream there is no buffer to flush so it does nothing.

Java Sockets passing between methods

I am just starting out with Java Socket Programming, and I have been reading literature on sockets here. The below code is a sample from a textbook I've taken which asks me to find the bug. Comparing with the literature though I am not seeing any bugs. The creation of the socket, bufferedreader, and printwriter seem correct, and they are surrounded in a try-catch block as well. The are properly "close()"ed in a try-catch block as well. Is there an error when passing these to process()? Any help would be appreciated.
import java.net.*;
import java.io.*;
class main{
public void process(PrintWriter out, BufferedReader in, Socket echoSocket){
//....
}
public void processData() {
Socket echoSocket;
PrintWriter out;
BufferedReader in;
try{
echoSocket = new Socket("server.company.com", 8081);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
}
catch (Exception e) {
System.err.println("Exception has occured");
return;
}
process(out, in, echoSocket);
try {
out.close();
in.close();
echoSocket.close();
}
catch(IOException e) {
System.err.println("IOException has occurred.");
}
}
}
Although, typos notwithstanding, one can only guess what the actual "bug" is, this code has an issue with error handling. Specifically, in the disposal of resources.
Discussion about resources
What are resources ?
Basically : any Java Object that relies on underlying OS level resources. Mostly : IO resources (input and output streams, channels), Sockets. But more importantly : if the "thing" you're using has a close, dispsose, shutdown or any of the like, it surely holds on to resources internally.
There are some exceptions (notably ByteArrayInputStream holds no resource but memory), but these are implementation details : if you stick to their interface (and you should, this is a "contract"), every stream should be closed.
Since Java 7, most of these objects in the Java API implement the AutoCloseable interface, but many 3rd parties have not necessarily ported this to their code (and maybe some can't for other reasons).
As one of the code reviewers at my company : I stop reading and I reject any code as soon as I do not see a secure call to the close method of a resource. By secure I mean inside a finally clause, that is guaranteed to be executed.
Rule of thumb about resources
Any resource obtained by your program should be freed in a finally clause (some even add : of its own).
What is the typical lifecycle of a resource
Well:
You obtain it
You use it
You release it
In your code, that is
ResourceObject myObject = null;
try {
myObject = getResource();
processResource(myObject);
} finally {
if(myObject != null) {
try {
myObject.close();
} catch (Exception e) {
// Usually there is nothing one can do but log
}
}
}
Since Java 7, if the resource object implements AutoCloseableyou have a new way of writing that, it's called the "try with resources".
try(ResourceObject myObject = getResource()) {
process(myObject);
}
You do not see the finally, but it's there, the compiler writes the finally clause for you in that case.
What about multiple resources ?
Well : multiple resources, multiple finallys. The idea is to separate the causes of failures in different finally clauses.
Say you want to copy a file...
public void myCopy() throws IOException {
InputStream source = null;
try {
source = new FileInputStream("yourInputFile");
// If anything bad happens, I have a finally clause that protects this now
OutputStream destination = null;
try {
destination = new FileOutputStream("yourOurputFile"); // If fails, my Input will be closed thanks to its own finally
performCopy(source, destination); // If this fail, my destination will also be closed thanks to its own finally
} finally {
if(destination!=null) { try { destination.close(); } catch (Exception e) {/* log*/ }}
}
} finally {
if(source!=null) { try { source.close(); } catch (Exception e) {/* log*/ }}
}
}
Or, with Java 7 syntax, we have the shorter (disclaimer : I have no Java7 right now, so can't really check if this compiles) :
try(
InputStream input = new FileInputStream("in");
OutputStream output = new FileOutputStream("out")) {
performCopy(input, output);
} catch(IOException e) {
// You still have to deal with it of course.
}
This is SO MUCH BOILERPLATE !
Yes it is. That's why we have libraries. One could argue you should not write such code. Use standard, well behaved libraries like commons IO, or use one of their utility methods. Or newer JDK methods like the Files API, and see how this works.
Commons IO has a handy IOUtils.closeQuietly() suite of methods for closing streams.
Try with resources Gotchas
There are ramifications in the "try with resources" call that go a bit deeper than that. These include: What if I want to do something with the exceptions that occur in the finally clause ? How do I differentiate that from an exception that would have occured during performCopy?
Another case is : what happens here :
try(Reader reader = new InputStreamReader(new FileInputStream("in"), "an encoding that is not supported")) {
// Whatever
}
It happens that an UnsupportedEncodingException is thrown but after the FileInputStream is instanciated. But as the FileInputStream is not the subject of the try clause, it will NOT be closed. An you have a File descriptor leak. Try that a thousand times, and your JVM will not be able to open files anymore, you OS will tell you "max number of open files exceeded" (ulimit generally does that in UNIX)
Back to your sockets
So what are your resources ?
Well, first, we can notice that you have only ONE true resource, your Socket instance, because the Socket javadoc says (javadoc):
* <p> Closing this socket will also close the socket's
* {#link java.io.InputStream InputStream} and
* {#link java.io.OutputStream OutputStream}.
So your Input and Output streams are tied to your Socket, and this is enough.
What's wrong with your code
Adding comments one your original code:
try{
echoSocket = new Socket("server.company.com", 8081);
out = new PrintWriter(echoSocket.getOutputStream(), true); // This can throw IOException
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream())); // Ditto
}
catch (Exception e) {
// If an exception was thrown getting any of the streams, we get there
System.err.println("Exception has occured");
// And you return without closing the socket. It's bad !
return;
}
// Let's assume everything worked, no exception.
process(out, in, echoSocket); // This may throw an exception (timeout, socket closed by peer, ...)
// that is uncaught (no catch clause). Your socket will be left unclosed as a result.
try {
out.close(); // This can fail
in.close(); // This too
echoSocket.close(); // And this too - although nothing you can do about it
}
catch(IOException e) {
// if out.close fails, we get here, and in.close and socket.close
// never got a chance to be called. You may be leaking resources
System.err.println("IOException has occurred.");
}
A safe implementation
Socket echoSocket = null;
try {
// open socket,
echoSocket = new Socket("server.company.com", 8081); // protected by finally
out = new PrintWriter(echoSocket.getOutputStream(), true); // protected
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream())); // protected
process(out, in, echoSocket); // Still protected
} catch (Exception e) {
// Your current error handling
} finally {
// Anyway, this close will be called if needs be.
if(echoSocket != null) {
try { echoSocket.close(); } catch (Exception e) { /* log */}
// See javadoc, this has closed the in & out streams too.
}
}
public void process(){PrintWriter out, BufferedReader in, Socket echoSocket){
should be
public void process(PrintWriter out, BufferedReader in, Socket echoSocket){
otherwise everything seems fine to me
Try this I think you missed one semicolon
public void processData() {
Socket echoSocket;
PrintWriter out;
BufferedReader in;
try{
echoSocket = new Socket("localhost", 8080);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
}
catch (IOException e) {
System.err.println("Exception has occured");
return;
}
process(out, in, echoSocket);
try {
out.close();
in.close();
echoSocket.close();
}
catch(IOException e) {
System.err.println("IOException has occurred.");
}
}
public void process (PrintWriter out, BufferedReader in, Socket echoSocket)
{
}

Interacting with another process Java

I am trying to interact with another process in Java. It goes like this...
Runtime rt;
Process pr=rt.exec("cmd");
then I send some commands to the process using...
BufferedReader processOutput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedWriter processInput = new BufferedWriter(new OutputStreamWriter(pr.getOutputStream()));
processInput.write("gdb");
processInput.flush();
I don't care about the output for now.. so I try to ignore it using..
while(processOutput.readLine() != null);
but this loops hangs forever. I know this is because process is still running and doesn't sends a null. I don't want to terminate it now. I have to send commands based on user Input and then get the output..
How to do this? In other words I want to flush the Process output stream or ignore it after executing some commands and read it only when I want to.
Use a separate thread to read the output. This way, as long as there is output it will be read, but will not block you.
For example, create such a class:
public class ReaderThread extends Thread {
private BufferedReader reader = null;
public ReaderThread(BufferedReader reader) {
this.reader = reader;
}
#Override
public void run() {
String line = null;
try {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
catch(IOException exception) {
System.out.println("!!Error: " + exception.getMessage());
}
}
}
And in your main class, instead of while(processOutput.readLine() != null);, call:
ReaderThread reader = new ReaderThread(processOutput);
reader.start();

Categories

Resources