In my Server code, I send different request to client and get back the response but only first read request is accessed, during accessing second read statement,it is unable to read Data bytes,my code is as followed.
private static boolean Rt_Request(int id,Object client)throws Exception
{
int size=5;
byte[] buf=new byte[size];
char[] cbuf=new char[32];
int byteRead; Socket s=(Socket)client;
BufferedReader in1= new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintStream out=new PrintStream(s.getOutputStream());
try {
buf[0]=0x02;
buf[1]=0x09;
buf[2]=0x01;
buf[3]=0x00;
buf[4]=0x03;
Thread.sleep(5000);
out.write(buf, 0, 5);
} catch(Exception e) {
System.out.println("Error Occured...."+e);
}
byteRead=0;
while(byteRead!=1) {
try {
byteRead=in1.read(cbuf, 0, 1);// Have problem on this line,here I am unable to read data bytes.
for(int i=0;i<byteRead;i++)
{
System.out.println(cbuf[i]);
}
if(byteRead==0)
{
System.out.println("Breaking.....");
return false;
}
}
catch(Exception e) {
System.out.println("Error Occured...."+e);
return false;
}
}
return true;
} catch(Exception e) {
System.out.println("System is not Connected..."+e);
return false;
}
almost tried every thing socket is not closed, read.available();,read.fully(); etc..unable to get the solution.I have written this function in the run method of TimerTask class.
any help will be greatly appreciated
the javadocs says BufferedReader#read(char[], int, int) Returns:
The number of characters read, or -1 if the end of the stream has been reached
since you do
byteRead=in1.read(cbuf, 0, 1);
in
while(byteRead!=1)
change it to
while(byteRead != -1)
byteRead=in1.read(cbuf, 0, 1);
This line only reads in one value and as you don't call it again before you enter the for loop, you should be getting 1 println of the value that was read in displayed in stdout.
read() blocks until at least one byte is available. Maybe you haven't sent it, or flushed it properly, or maybe you are creating multiple BufferedReaders on the same socket.
NB bytesRead can never be zero after a successful read(cbuf, 0, 1).
The read method of the underlying InputStream will block (i.e. hang/wait) if no data is available.
This method blocks until input data is available, end of file is detected, or an exception is thrown.
I strongly suspect this is the case.
You can check this by calling in1.ready() on the reader.
Flush the output buffer
out.flush();
after writing the bytes, or they may get buffered locally.
Related
Following scenario that explains my problem.
I've a PLC that acts as a server socket program. I've written a Client Java program to communicate through socket communication with the PLC.
Steps that take place in this process are:
1) For each second my Client program happen to communicate with the PLC, read the data in stream, store the data temporarily in a ByteArrayOutputStream and closing both input stream and socket. Following snippet gives the idea
try {
socket = new Socket(host, port);
is = socket.getInputStream();
outputBuffer = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int read;
if((read = is.read(buffer)) != -1) {
outputBuffer.write(buffer, 0, read);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
System.out.println("Before closing the socket");
try {
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("After closing the socket");
} catch (Exception e) {
e.printStackTrace();
}
}
2) Processing stored data according to my requirement is what I'm trying to do. So for every 1 second, client program connects to Server, read the data(if data is present), store the data, close socket and process it. And it has to happen for a very long run, probably till the Server program is on. And that may happen till for every few weeks.
3) Problem what I'm facing is, I'm able to run the above show for 1-2 hours, but from then, Client Program unable to fetch the data from the Server Program(PLC in this case), though both are connected through socket. I.e 128 bytes of data present, but Client program isn't able to read that data. And this started happening after program run successfully for almost 2hours
4) Please find the brief code which may help for you to look into.
public class LoggingApplication {
public static void main(String[] args) throws NumberFormatException {
if (args.length > 0 && args.length == 2) {
String ipAddress = mappingService.getIpAddress();
int portNo = (int) mappingService.getPortNo();
ScheduledExecutorService execService = Executors.newScheduledThreadPool(1);
execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);
} else {
throw new IllegalArgumentException("Please pass IPAddress and port no as arguments");
}
}
}
Runnable Code:
public class MyTask implements Runnable {
public ScheduledExecutorService execService;
private String ipAddress;
private int portNo;
private ConfigurationMappingService mappingService;
private MySocketSocketUtil mySocketSocketUtil;
public MyTask(ScheduledExecutorService execService, String ipAddress, int portNo, ConfigurationMappingService mappingService) {
this.execService = execService;
this.ipAddress = ipAddress;
this.portNo = portNo;
this.mappingService = mappingService;
}
public void run() {
MySocketSocketUtil mySocketSocketUtil = new MySocketSocketUtil(ipAddress, portNo);
execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);
mySocketSocketUtil.getData(); //It's able to fetch the data for almost 2 hours but from then, it's just getting empty data and it's keep on giving empty data from then. and so on.
/*
*
*Some code
*/
}
}
Here's where, I'm having the problem
mySocketSocketUtil.getData(); is able to fetch the data for almost 2 hours but from then, it's just getting empty data and it's keep on giving empty data from then. and so on. It's a big question I know, And I want to understand what might have gone wrong.
Edit: I'm ignoring the condition to check end of the stream and closing a socket based on it is because, I knew I'm going to read first 1024 bytes of data only always. And So, I'm closing the socket in finally block
socket = new Socket(host, port);
if(socket != null && socket.isConnected())
It is impossible for socket to be null or socket.isConnected() to be false at this point. Don't write pointless code.
if((read = is.read(buffer)) != -1) {
outputBuffer.write(buffer, 0, read);
};
Here you are ignoring a possible end of stream. If read() returns -1 you must close the socket. It will never not return -1 again. This completely explains your 'empty data':
from then, it's just getting empty data and it's keep on giving empty data from then, and so on
And you should not create a new Socket unless you have received -1 or an exception on the previous socket.
} else {
System.err.println("Socket couldn't be connected");
}
Unreachable: see above. Don't write pointless code.
You should never disconnect from the established connection. Connect once in the LoggingApplication. Once the socket is connected keep it open. Reuse the socket on the next read.
I think there are couple of points you need to fix before getting to the solution to your problem. Please try to follow the following suggestions first:
As #EJP said this code block is not needed.
if(socket != null && socket.isConnected()) {
also you are using a byte array of length 1024 and not using while or for loop to read the data stream. Are you expecting only a block of data which will never exceed 1024 bytes?
byte[] buffer = new byte[1024];
int read;
if((read = is.read(buffer)) != -1) {
This is also not needed as it is unreachable.
} else {
System.err.println("Socket couldn't be connected");
}
Can you explain the data stream behavior you are expecting?
Last but not the least is.read(buffer) is a blocking call so if there is no data to read yet, it will hold the thread execution at that point.
Please try to answer the questions I have asked.
#KishoreKumarKorada from your description in the comment section, it seems like you are monitoring the data change on server side. Socket stream works in a read-once fashion. So,
First thing is, you need to request from server every time and the server needs to RESEND the data on every request.
Second, the way you presented is more like you are operating on byte level, which is not very good way to do that unless you have any legitimate reason to do so. The good way is to wrap the data in JSON or XML format and send it over the stream. But to reduce bandwidth consumption, you may need to operate on byte stream sometimes. You need to decide on that.
Third, for monitoring the data change, the better way is to use some timestamp to compare when the data has changed on the server side and what is the timestamp stored on the client side, if they match, data has not changed. Otherwise fetch the data from the server side and update the client side.
Fourth, when there is data available that you are not able to read, can you debug the ins.read(...) statement to see if its getting executed and the execution goes inside the if block or if statement is evaluated to false? if true then examine the read value and let me know what you have found?
Thanks.
I need to get error message while firing any command using JSch.
Currently I am using below code to get output of tail command, but if the file does not exist, I should get the error as output (which I am not getting).
public String getOutput() {
LOGGER.debug("[getOutput]");
StringBuffer output = new StringBuffer();
InputStream in = null;
if (channel != null && channel.isConnected()) {
try {
in = channel.getInputStream();
byte[] tmp = new byte[1024];
while (true) {
LOGGER.debug("[getOutput] in while");
while (in.available() > 0) {
LOGGER.debug(in.available());
int i = in.read(tmp, 0, 1024);
if (i < 0)
break;
output.append(new String(tmp, 0, i));
}
if (channel.isClosed()) {
LOGGER.debug("[getOutput] Channel is closed, so breaking while loop");
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
channel.disconnect();
}
} else {
System.out.println("Channel is disconnected");
}
return output.toString();
}
Is there any way i could get the error message too?
Thanks in advance.
The error are usually written to the error output. You can read the error output using getErrStream.
Note that you need to read the standard output (getInputStream) and the error output in parallel, not in sequence. I mean that you cannot just clone your while loop, you have for getInputStream, for getErrStream. You need to have one loop, reading from both (read what's available in one, read what's available in the second, wait for new data and repeat)
When you read first one and then the other, if the latter output is large, its output buffer gets full, the command stops, never finishing. So if you keep waiting for the first output to close, you deadlock with the server.
Note that the "Auth failed" is not an error outputted by a command. It's an exception thrown by the JSch library. So it's irrelevant to your code.
If you have a ChannelExec to call a remote command you can use channel.getExitStatus() to get the (non null) numeric exec code in a failure situation (as long as the shell and command you are using are well behaved).
I have a little problem with my InputStream.
Here the code :
public byte[] getBytes(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int read = 0;
byte[] buffer = new byte[1024];
while ( 0 < (read = in.read(buffer))) {
Log.v(TAG,"buffering...");
out.write(buffer,0,read);
Log.v(TAG, "bufffered data size : "+out.size());
}
Log.v(TAG, "close out");
out.close();
Log.v(TAG, "getBytes finish");
return out.toByteArray();
}
In my logs I have "buffering..." and the data size until the length of the byte array i send but when the size is the max, nothing happen. No error, no crash, juste nothing, like if we stay in the while without make the loop...
Someone have any idea ?
And... sorry for my english.
Edit:
I added
if(is.available()==0){
Log.v(TAG, "time to sleep");
Thread.sleep(200);
if(is.available()==0)
break;
}
at the end of my while and it work !
Thank you for your help guys !
Well, in.read(buffer) will block until it receives data, it reaches the end of the file, or an exception is thrown (from here). My guess is that its still just waiting on more input from the InputStream.
Also, you should close the input stream after you finish reading from it.
I got some stupid problem, I don't know what am i doing wrong.
I wrote client and server, client is working properly. I checked that output stream works properly in client there are bytes, but in server when a client connected, method in.avaible() returns always zero? Why?
SOme code of my server:
try{
serverSocket = new ServerSocket(port);
}
catch (IOException e){
System.err.println("Could not listen on port: " + port);
return false;
}
System.out.println("Server Started");
txtServer.setText("Server wystartowaĆ");
return true;
}
else{
txtPort.setText("Brak Portu!");
txtPort.setBorder( BorderFactory.createLineBorder(Color.RED) );
return false;}
}
#Override
public void run() {
try{
clientSocket = serverSocket.accept();
data.clear();
System.out.println("Client connected");
cl_obs = new Client_obs(clientSocket, data);
Thread t = new Thread(cl_obs);
t.start();
}
catch (IOException e){
System.err.println("Accept failed.");
System.exit(1);
}
}
package Server;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class Client_obs implements Runnable {
private InputStream in;
private data data;
private Socket clientSocket = null;
public Client_obs(Socket cl, data data1){
clientSocket =cl;
data = data1;
}
#Override
public void run() {
try {
in = clientSocket.getInputStream();
byte[] data1 = new byte[in.available()];;
for (int i=0; i<data1.length; i++){
data1[i] = (byte)in.read();
}
data.setData(data1);
data.displayMSG(data.getdata());
in.close();
clientSocket.close();
}
catch(IOException e){
e.printStackTrace();
}
}
}
That's a perfectly legal implementation.
Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream. The next invocation might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes.
Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.
A subclass' implementation of this method may choose to throw an IOException if this input stream has been closed by invoking the close() method.
The available method for class InputStream always returns 0.
You should look at the documentation of the available method. For some implementations its not possible to know the exact number of bytes available. Therefore 0 is a valid result for those implementations:
Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.
...
The available method for class InputStream always returns 0.
Instead of available() you can use reflection as it was provided here: Determine the size of an InputStream .
Simple recipe for ByteArrayInputStream:
ByteArrayInputStream wrapper = (ByteArrayInputStream)inputStream;
Field field = ByteArrayInputStream.class.getDeclaredField("buf");
field.setAccessible(true);
byte[] buffer = (byte[])field.get(wrapper);
return buffer.length;
this function when called in a loop is sometimes giving null as outstream while other times not .. any reason why ? i am writing the outstream into text file sometimes i get empty text file . why ? if i run the loop 20 times .. i sometimes get empty text file on 3 random occasions sometimes 4 or 2 random occasions. what should i do ?
public void decrypt(InputStream in, OutputStream out) {
try {
// Bytes read from in will be decrypted
in = new CipherInputStream(in, dcipher);
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
}
catch (java.io.IOException e) {
}
}
I think this happens because you are closing the output stream in your function. This way, the next iteration of your cycle will try to write to an already closed output stream. It will throw an IOException but you are ignoring it. Try closing the output stream after your loop and not in the method.
InputStream in = null;
OutputStream out = null;
try {
in = Initialize input stream
out = Initialize output stream
for (int i = 0; i < 10; i++) {
decrypt(in, out);
}
}finally {
try {
if (out != null)
out.close();
}finally {
if (in != null)
in.close();
}
}
If an exception is thrown by any code in your try block , it is ignored (since you have nothing in your catch clause.
You might want to :
actually do something in the catch clause (at least print the message of the exception - try e.printStackTrace())
instead of doing the out.close() call in the try block, do it in a finally clause after the catch block (so that it happens even if there is an error)
also , as pointed out by bruno, if you're always reusing the same output stream for evey calls of decrypt, you should not close it inside the function. However you might want to flush() it inside you loop.
you should definitely fix this part of your code:
catch (java.io.IOException e) {
}
and do at least some logging there. That way you'll find out why you have the problem you described.
"Never close something that you haven't opened" - don't know if that's a golden rule, but it nearly always leads to trouble when you close a resource in a subroutine - either the ressource is closed next time you need it or the resource is not closed because you changed the code...