From what I understand the whole point of end of stream is to tell the input stream when to stop reading data, which makes sense in file streams, but when it's an ObjectInputStream why would I want it to stop reading objects if I might send another one in the future.
In my case the ObjectInputStream throws an EOFException whenever it decides that something is causing the end of stream.
Code segment:
Sending:
public synchronized void sendCommand(CommandBase command){
try {
commandOutputStream.writeUnshared(command);
commandOutputStream.flush();
System.out.println("Sent " + command.getAction().toString());
} catch (IOException e) {
System.out.println("Failed to send " + command.getAction().toString());
try {
commandOutputStream.close();
running = false;
this.dispose();
System.out.println("Closing command output stream");
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
Receiving
while(going && tcpSender.running){
//Get action from stream
try {
System.out.println("Available bytes: " + commandInputStream.available());
Object command = ((CommandBase) commandInputStream.readObject());
System.out.println("Action received");
if (command instanceof CommandBase) {
if(((CommandBase)command).getAction().equals(ActionType.MouseAction)){
System.out.println("Mouse action");
//JOptionPane.showMessageDialog(null, "Received Mouse Action");
((MouseCommand)command).doAction(operator);
}else if(((CommandBase)command).getAction().equals(ActionType.KeyboardAction)){
System.out.println("Keyboard action");
//JOptionPane.showMessageDialog(null, "Received Keyboard Action: " + ((KeyboardCommand)command).toString());
((KeyboardCommand)command).doAction(operator);
}else if(((CommandBase)command).getAction().equals(ActionType.CheckBooleanAction)){
System.out.println("Check boolean action");
udpSender.notifyThis((CheckBooleanCommand)command);
}else{
//JOptionPane.showMessageDialog(null, "Received unknown command " + ((CommandBase)command).getAction().toString());
System.out.println("Action type is: " + ((CommandBase)command).getAction().toString());
}
}
} catch (EOFException e) {
System.out.println("EOF-Exception - end of stream reached");
e.printStackTrace();
continue;
} catch(IOException e){
System.out.println("IO-Exception - Unable to read action \n Closing socket");
try {
commandInputStream.close();
System.out.println("Closed command input stream");
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
going = false;
tcpSender.running = false;
} catch (ClassNotFoundException e) {
System.out.println("Class not found - failed to cast to Action");
e.printStackTrace();
}
}
TL;DR: How does the ObjectInputStream decide that it's the end of a stream, and what causes it?
And how can I solve this problem?
Error message:
`
java.io.EOFException at
java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown
Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
How does the ObjectInputStream decide that it's the end of a stream
It happens when ObjectInputStream attempts to read from the underlying stream, and that stream returns -1 ... which means that the end-of-stream has been reached.
and what causes it?
In this case, the most likely explanation is that the remote end (the sender) has closed its socket, or it has crashed ... which will cause the socket to close.
(It is theoretically possible that the connection has been broken, but that is only likely to happen in obscure circumstances, so lets ignore that.)
And how can I solve this problem?
You need to understand why the sending end has closed the socket. Unfortunately, we cannot tell why that is because the code you have provided is not an MCVE.
Related
Normally when I use
r = new BufferedReader(new InputStreamReader(receivedSocketConn1.getInputStream()));
then I use
int nextChar = 0;
while ((nextChar=r.read()) != -1)
{
}
Now I am going to use byte level
r = new DataInputStream(new BufferedInputStream(receivedSocketConn1.getInputStream()));
so the first byte I read is this
try {
while(true){
if (r.readByte() != 0x7E) // start byte
{
// ah oh, something went wrong!!
receivedSocketConn1.close();
return;
}
int bodyLen = r.readUnsignedShort(); // message body nature (body length)
byte serialNum1 = r.readByte();// message serial number
byte[] messageBody = new byte[20]; // message body
r.readFully(messageBody);
if (r.readByte() != 0x7E) // end byte
{
// ah oh, something went wrong!!
receivedSocketConn1.close();
return;
}
}
}
catch (SocketTimeoutException ex)
{
System.out.println("SocketTimeoutException has been caught");
ex.printStackTrace();
}
catch (IOException ex)
{
System.out.println("IOException has been caught");
ex.printStackTrace();
}
finally
{
try
{
if ( w != null )
{
w.close();
r.close();
receivedSocketConn1.close();
}
else
{
System.out.println("MyError:w is null in finally close");
}
}
}
You see it always goes into the finally block after I do the 7e, thereafter it cuts the link. I would like to keep the link for some time. But before that, I want to run a for loop for the look for the -1 in this scenario. How to I implement that?
You don't need to handle -1 in this situation.
If you read the documentation, it says:
InputStream::read()
Returns:
the next byte of data, or -1 if the end of the stream is reached.
DataInputStream::readByte()
Throws:
EOFException - if this input stream has reached the end.
IOException - the stream has been closed and the contained input stream does not support reading after close, or another I/O error occurs.
The same goes for all of the DataInputStream reading methods.
So, all you have to do is read values from the DataInputStream normally and let it throw an exception if the socket gets closed by the peer. You are already doing exactly that (EOFException extends IOException and will be caught in your catch (IOException ex) block). You are over-thinking the problem.
That being said, if reading the 0x7E byte is throwing an exception (which readByte() call is failing? Which exception is being thrown?), then you are doing something wrong. For instance, this question is based on code I gave you yesterday for another question, but the code you have shown in this question is incomplete based on the earlier code. That omission would easily cause the second if (r.readByte() != 0x7E) to evaluate as false and close the connection.
Try something more like this instead:
w = new DataOutputStream(new BufferedOutputStream(receivedSocketConn1.getOutputStream()));
r = new DataInputStream(new BufferedInputStream(receivedSocketConn1.getInputStream()));
try
{
while(true)
{
if (r.readByte() != 0x7E) // start byte
throw new RuntimeException("Incorrect start byte detected");
int messageID = r.readUnsignedShort(); // message ID
int bodyLen = r.readUnsignedShort(); // message body nature (body length)
byte[] phoneNum = new byte[6];
r.readFully(phoneNum); // device phone number
int serialNum = r.readUnsignedShort(); // message serial number
byte[] messageBody = new byte[bodyLen]; // message body
r.readFully(messageBody);
byte checkCode = r.readByte(); // check code
if (r.readByte() != 0x7E) // end byte
throw new RuntimeException("Incorrect end byte detected");
// TODO: validate checkCode if needed...
// ...
// if (checkCode is not valid)
// throw new RuntimeException("Bad checkCode value");
// process message data as needed...
}
}
catch (SocketTimeoutException ex)
{
System.out.println("SocketTimeoutException has been caught");
ex.printStackTrace();
}
catch (EOFException ex)
{
System.out.println("Socket has been closed");
}
catch (IOException ex)
{
System.out.println("IOException has been caught");
ex.printStackTrace();
}
catch (RuntimeException ex)
{
System.out.println(ex.getMessage());
ex.printStackTrace();
}
finally
{
w.close();
r.close();
receivedSocketConn1.close();
}
I put the declaration in the while loop, and the program would not running and also does not return any error. I suspect the while loop become an infinite loop.
try
{
while (true)
{
inputStream = new ObjectInputStream (new FileInputStream (fileName));
Ship copyObject = (Ship) inputStream.readObject();
String nameCompany = copyObject.getCompanyName();
if (compName.equalsIgnoreCase(nameCompany)){
listShipName += (copyObject.getShipName() + ", ");
numberOfShip ++;
}
}
}
catch (EOFException e)
{
}
catch (Exception e)
{
e.printStackTrace();
}
But if I put the declaration of input stream out of the while loop, the program runs successfully. Can someone explain why this happens?
try
{
inputStream = new ObjectInputStream (new FileInputStream (fileName));
}
catch (Exception e)
{
e.printStackTrace();
}
try
{
while (true)
{
Ship copyObject = (Ship) inputStream.readObject();
String nameCompany = copyObject.getCompanyName();
if (compName.equalsIgnoreCase(nameCompany)){
listShipName += (copyObject.getShipName() + ", ");
numberOfShip ++;
}
}
}
catch (EOFException e)
{
}
catch (Exception e)
{
e.printStackTrace();
}
You're reopening your file on every iteration through the loop, which means you are only ever reading the first object from the file. But you're reading the same object over and over again.
As well as opening your file only once, you really should try to detect the end of file without throwing an exception. As a matter of style, exceptions should be thrown when things go wrong, not as a matter of course.
Now I realize that in each iteration, I reopen the input stream, so the loop would not reach to the end of the file, and it becomes infinite.
I am running another jar with this code:
(I am updating a gui in some parts , so dont feel confused.)I get an IO Exception (Stream Closed) here:
if((line = readr.readLine()) != null){
Thats the full code:
if(!data.serverStarted()){
try{
data.updateConsole("Starting server!");
String fileDir = data.dir + File.separator + "craftbukkit.jar";
Process proc = Runtime.getRuntime().exec("java -Xmx2048M -jar "+"craftbukkit.jar"+" -o true --nojline");
data.setOutputStream(proc.getOutputStream());
InputStream is = proc.getErrorStream();
}catch(IOException ex){
ex.printStackTrace();
}
BufferedReader readr = new BufferedReader(new InputStreamReader(is));
data.setServerStarted(true);
String line;
while(data.serverStarted()){
try {
if((line = readr.readLine()) != null){
data.updateConsole(line);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
readr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}else{
data.updateConsole("You have already started your server!");
}
You have a while loop that closes readr on every pass. The next time it gets to the try block, readr is closed. Perhaps you intended to put the try/catch block around the while loop?
You are closing the reader inside the loop that reads from it. You need to close it outside of the loop:
try {
String line;
while (data.serverStarted() && ((line = readr.readLine()) != null)) {
try {
data.updateConsole(line);
} catch (IOException e) {
e.printStackTrace();
}
}
} finally {
try {
readr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
I am surprised that this code even compiles.
You declare the actual InputStream is inside the try/catch at the beginning, but that makes it only visible inside that block. So whatever you give to the BufferedReader a few lines below is something else and most likely not what you think it is.
In addition your while(data.serverStarted()) does not check if the stream is still open, and later you only use a single if check (again with no check if the stream is open), so you'll only read one single line at best.
I have a feeling that you had a bad OutOfCoffeeException while writing this code. ;)
I have two file-to-string processes in my app (one actually deals with an asset file).
If I repeat either of these processes a few times on the same file, I get OutOfMemoryErrors.
I suspect it might be because I'm not closing the streams properly and therefore maybe causing multiple streams to be created, and this is perhaps causing my app to run out of memory.
Here is the code of the two processes:
My asset-file-to-string process.
As you can see, I have have something in place to close the stream but I don't know if it's formatted properly.
try
{
myVeryLargeString = IOUtils.toString(getAssets().open(myAssetsFilePath), "UTF-8");
IOUtils.closeQuietly(getAssets().open(myAssetsFilePath));
}
catch (IOException e)
{
e.printStackTrace();
}
catch(OutOfMemoryError e)
{
Log.e(TAG, "Ran out of memory 01");
}
My file-to-string process.
I have no idea how to close this stream (if there is even a stream to close at all).
myFile01 = new File(myFilePath);
try
{
myVeryLargeString = FileUtils.readFileToString(myFile01, "UTF-8");
}
catch (IOException e)
{
e.printStackTrace();
}
catch(OutOfMemoryError e)
{
Log.e(TAG, "Ran out of memory 02");
}
It's difficult to say what may cause OOME but closing should be like this
InputStream is = getAssets().open(myAssetsFilePath);
try {
myVeryLargeString = IOUtils.toString(is, "UTF-8");
} finally {
IOUtils.closeQuietly(is);
}
We have java socket connection application which receives data from gps devices. The problem now at times we received corrupted data and checked on the device logs everything is fine. First BufferedReader was used and suspected to be the culprit. The we moved to inpustream also still having problem. The corruption is at random and not fixed interval. Below is the snippet of codes.
public void run() {
String completeMessage="";
//BufferedReader readerBuffer = null;
InputStream is = null;
BufferedWriter writeBuffer = null;
try {
//readerBuffer = new BufferedReader(new InputStreamReader(sockConn1.getInputStream()));
is = sockConn1.getInputStream();
writeBuffer = new BufferedWriter(new OutputStreamWriter(sockConn1.getOutputStream()));
int readChar=0;
sockConn1.setSoTimeout(120000);
//dbConnection = connectionPool.getConnection();
//dbConnection.setAutoCommit(false);
int readChar
while ((readChar=is.read()) != -1)
{
System.out.println("Char value: "+(char)readChar) ;
if (readChar == '*') {
try {
//writeBuffer.write("##\r\n\r\n");
//writeBuffer.flush();
//db processing
dbConnection.commit();
}
catch (SQLException ex){
ex.printStackTrace();
try{
dbConnection.rollback();
}
catch (Exception rollback){
rollback.printStackTrace();
}
}
catch (Exception e){
e.printStackTrace(System.out);
try{
dbConnection.rollback();
}
catch (Exception rollback){
rollback.printStackTrace(System.out);
}
}
finally{
try{
if ( dbStmt != null ){
dbStmt.close();
}
}
catch(SQLException ex){
ex.printStackTrace(System.out);
}
}
completeMessage="";
}
}
}
catch (SocketTimeoutException ex){
ex.printStackTrace();
}
catch (IOException ex){
ex.printStackTrace();
}
catch (Exception ex){
ex.printStackTrace();
}
finally{
try{
if ( dbConnection != null ){
dbConnection.close();
}
}
catch(SQLException ex){
ex.printStackTrace();
}
try{
if ( writeBuffer != null ){
writeBuffer.close();
}
}
catch(IOException ex){
ex.printStackTrace(System.out);
}
}
}
There is a problem. You read/write binary data as text:
InputStream, OutputStream = binary data
Reader, Writer = text
This is bridged by:
new InputStremReader(inputStream, charEncoding)
new OutputStreamWriter(outputStream, charEncoding)
And String to byte is bridged by:
new String(bytes, charEncoding)
string.getBygtes(charEncoding)
Where charEncoding is an optional parameter, defaulting to the operation system encoding.
With UTF-8, the Unicode multi-byte encoding, you are fast into troubles if done wrong. Also other encodings have problematic bytes.
So do not use Reader/Writer.
The read() delivers an int, -1 for end-of-file, a byte value otherwise.
It seems your test with read() throws a byte away, and the subsequent read does not test for -1.
It is not clear what character encoding is used here.
When you deal with character streams then it is nearly always a good idea to explicitly provide the character encoding to en-/decode the byte stream.
In my opinion it is most likely a character encoding issue here. Use the same encoding on both sides and you won't have trouble with Reader/Writer.