Sending a hashtable over a socket continued

Hello,
This is a continuation of a previous question (). I have written this code which is a thread that is spawned upon the successful connection of a serversocket. All it is supposed to do is collect the hashtable sent by the client, and count the # of hashtables recieved (this code is only used for proofing at the moment, once I have this figured out I will make it quite a bit more elegant). Anyways I have the following problems with it.

#1 - Why when I terminate the client feeding the hashtables does it not properly recognize the connection as broken and just keep spitting Exceptions?

#2 - Why does it throw a java outofmemory exception after receiving consistently 32768 hashtables?

Correct answers to these questions is worth 500 points. Code is below.

Thanks,
Rick

import java.net.*;
import java.io.*;
import java.util.*;

public class dataThread extends Thread {
    private Socket socket = null;

    public dataThread(Socket socket)
    {
          super();
          this.socket = socket;
    }

    public void run()
    {
          int count = 0;
          try
          {
                ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
                
                while (socket.isClosed() == false)
                {      
                try
                {
                      Hashtable hs = (Hashtable) in.readObject();
                
                        //data was received
                      count++;
                            
                      System.out.println(count);
                
                }
                catch (IOException e)
                {
                      System.out.println("Error while reading hashtable.");
                    
                }
                catch (ClassNotFoundException cnfe)
                {
                      System.out.println("Error while reading hashtable. 2");
                }
                }
            }
            catch (IOException ie)
            {
            }
            
   
          //thread is done
          try
          {
              socket.close();
          } catch (IOException e)
          {
                e.printStackTrace();
          }
    }
}

richardsimnettAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

richardsimnettAuthor Commented:
richardsimnettAuthor Commented:
Also, I have tried replacing:

 while (socket.isClosed() == false)

with

  while (socket.isConnected() == false)
 
to fix the connection break error, and it made no difference.

Thanks,
Rick
Tommy BraasCommented:
You can't trust socket.isConnected() for detecting connection state during a connection except immediately after connect to validate that a connection was established. socket.isClosed() keeps state whether the socket was closed after a call to socket.close().
Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

Tommy BraasCommented:
Please provide the stack trace from your OOM?
richardsimnettAuthor Commented:
orangehead911,
Ok so if neither of those give me the actual socket connection state, how do I get it?

Stack Trace is on the way.

Thanks,
Rick
Mayank SAssociate Director - Product EngineeringCommented:
That's the trick - until you do any data-transfer, you cannot trust isConnected (). It stores the result of the last I/ O operation (read or write) - if it was successful, it will return a true otherwise a false. But if the connection borke after that I/ O, you can only come to know about it when you try to read or write again.

I would suggest that you send a "CLOSE" packet from the client so that the server closes the socket gracefully at its end, instead of waiting for an exception to be thrown and then displaying the error-message.
Tommy BraasCommented:
Only actual I/O can determine if a socket is connected.

Also, just like socket communication initiation is done in a certain sequence, so should socket termination.
Tommy BraasCommented:
Does the client code cose its connection to the server when it is done sending the maps?
richardsimnettAuthor Commented:
java.io.StreamCorruptedException
        at java.io.ObjectInputStream.readObject0(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at dataThread.run(dataThread.java:25)
java.io.StreamCorruptedException
java.lang.OutOfMemoryError
richardsimnettAuthor Commented:
Orangehead911,
yes it does, however, that is not the issue I am concerned about. I am more concerned about actual network errors etc, taking the process out. The project is meant to transmit large amounts of data to remote facilities, obviously in between network conditions may be a factor, so I need to be able to tell when a connection is dropped, so that I can log the error, and attempt to reopen the connection from the client. For the server, I need it to detect a break so that the thread can terminate.

Thanks,
Rick

richardsimnettAuthor Commented:
mayankeagle,

that cant be true, if it was then my loop up there would terminate after throwing 1 exception (with isConnected as well) as the i/o event would trigger a false value when it throws an exception. This thing just loops forever throwing the exception. At this point I am assuming I have to rely on exceptions in order to tell if a connection is broken, and that doesnt seem very efficient to me.

Thanks,
Rick
Mick BarryJava DeveloperCommented:
you continue to try and read after a i/o error. once you get an error you need to end the thread.
you can do this by moving the loop *inside* the try/catch block
richardsimnettAuthor Commented:
objects,
hehe... your right! I totally overlooked the retartedness of that thread code. Heres the new code after your suggestion:

import java.net.*;
import java.io.*;
import java.util.*;

public class dataThread extends Thread {
    private Socket socket = null;

    public dataThread(Socket socket)
    {
          super();
          this.socket = socket;
    }

    public void run()
    {
          int count = 0;
          ObjectInputStream in;
          
               try
               {
                in = new ObjectInputStream(socket.getInputStream());
             
                while (socket.isClosed() == false)
              {      
                            Hashtable hs = (Hashtable) in.readObject();
                      
                            //data was received
                            //so feed it to PMTA
                            count++;
                            
                            System.out.println(count);
              }
                
          }
          catch (Exception e)
          {
                e.printStackTrace();
                e.getMessage();
          }      
            
          //thread is done
          try
          {
              socket.close();
          } catch (IOException e)
          {
                e.printStackTrace();
          }
    }
}

Any idea about how to correct the out of memory error?

Thanks,
Rick

Mick BarryJava DeveloperCommented:
are u still getting it?
 
Mayank SAssociate Director - Product EngineeringCommented:
>> that cant be true,

What can't be true?

>> if it was then my loop up there would terminate after throwing 1 exception (with isConnected as well)

isConnected () will not check for network connection - it will just return the status of the last I/O.

>> At this point I am assuming I have to rely on exceptions in order to tell if a connection is broken

Did you try the approach which I suggested? Sending a "CLOSE" packet so that the server gracefully closes it.

>> yes it does, however, that is not the issue I am concerned about

If you send just one hashtable from the client and close the connection, why do you loop again at the server, waiting for more hash-tables? The other hash-tables will come in the other threads, right? Just wait for the hash-table to come once and then close the socket.

You probably get out-of-memory error because you create too many threads and keep them alive when they are not required. You should dispose of them when the clients are disconnected.
richardsimnettAuthor Commented:
objects,
yep... at the exact same place. Same exact error too.

Thanks,
Rick
Mayank SAssociate Director - Product EngineeringCommented:
If the client closes the connection, you will get the exception, of course....
Mayank SAssociate Director - Product EngineeringCommented:
>> You should dispose of them when the clients are disconnected.

By exiting out of the loop. In fact, if you read only one hash-table per client, you don't even need a loop.
richardsimnettAuthor Commented:
mayankeagle,
>>What can't be true?
>>isConnected () will not check for network connection - it will just return the status of the last I/O.

Sorry I have to take that back after objects pointed out putting the loop in the try, the way it was originally structured that wouldnt have worked.

>>Did you try the approach which I suggested? Sending a "CLOSE" packet so that the server gracefully closes it.

The code will use a CLOSE command as the protocol, however, at the moment I am more concerned about ironing out all the exception handling. Considering this will work over the internet (not a local network) I have to compensate, and correct errors that may occur. Such as dropped connections, timeout errors, etc.

>>If you send just one hashtable from the client and close the connection, why do you loop again at the server, waiting for more hash-tables? The other hash->>tables will come in the other threads, right? Just wait for the hash-table to come once and then close the socket.

The intent is that it will loop as designed above. It should receive limitless #'s of hashtables until either A) the datasend session is complete (as designated by the to-be-designed protocol) or B) a network error occurs.

>>You probably get out-of-memory error because you create too many threads and keep them alive when they are not required. You should dispose of them when >>the clients are disconnected.

Also this is a single thread running. I open 1 connection and run a single thread. There aren't multiples, nor is this in the spec of the project.

Thanks,
Rick
Mayank SAssociate Director - Product EngineeringCommented:
>> or B) a network error occurs.

You should put the while () inside the try block, then, as suggested.

>> The code will use a CLOSE command as the protocol,

Is it implemented? I don't see it.

>> Also this is a single thread running. I open 1 connection and run a single thread

For multiple clients, you should use multiple dedicated threads at the server. Refer to this:

http://www.experts-exchange.com/Programming/Programming_Languages/Java/Q_21757720.html#16084277
richardsimnettAuthor Commented:
mayankeagle,

>>You should put the while () inside the try block, then, as suggested.

The while has been put in the try block, and the code has been reworked a bit (see the post to objects above).

>>Is it implemented? I don't see it.

The actual transfer protocol hasnt been designed yet. I just know that it will be based on hashtables in and text out. After each hashtable is processed I am going to have it return an OK response with some diagnostic information. The client will send a hashtable with the embedded command CLOSE as the final hashtable, which when implemented the thread will catch and terminate.
As I said before at this point I am simply trying to eliminate all of the exception issues that can arise with connections over the internet. I will concentrate on the protocol after this.

>>For multiple clients, you should use multiple dedicated threads at the server.

No the server will only receive a single connection from a single ip, and will only have a single thread serving the server socket. It will never need to support multiple worker threads for the server socket.

At the moment the only issue I still have is the Out Of Memory Issue. Which occurs exactly 37635 hashtables after the transfer begins. It occurs when I try to read the object after hashtable #37635 (the stack trace says java.io.StreamCorruptedException... see above).

Thanks,
Rick

Mick BarryJava DeveloperCommented:
On the sending side try calling reset() on the OOS after sending each Hashtable.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
richardsimnettAuthor Commented:
objects,
IT WORKS! Thanks a whole bunch, what made you think of that?

Thanks,
Rick
Mick BarryJava DeveloperCommented:
object streams use a cache, and reset() clears it.
richardsimnettAuthor Commented:
I totally overlooked that. Thanks for the help.

-Rick
Mayank SAssociate Director - Product EngineeringCommented:
>> It will never need to support multiple worker threads for the server socket.


>> On the sending side try calling reset() on the OOS after sending each Hashtable

You mean flush () ?
Mayank SAssociate Director - Product EngineeringCommented:
>> >> It will never need to support multiple worker threads for the server socket.

Sorry I forgot to answer to that. Well, see the link which I posted above for a multi-threaded server. I didn't mean that you need multiple threads for the server socket. The server socket will be in one thread (the main-thread) and whenever it receives a client connection, it will spawn a new thread like your "dataThread" class, and hand over the socket to it (I guess, unknowingly, this is what you do anyway). That way the server's main-thread can also go back to the job of listening and it will serve two purposes - a) multiple clients can be handled if required, it anyway supports 1 client also, b) if the current client gets disconnected, it can connect again and it will be handled as another client by another thread (the previous thread will come out of the while () loop and the run () method, and die).
Mayank SAssociate Director - Product EngineeringCommented:
Just for the sake of curiosity, can you also try flush () instead of reset () and see if it works?
Tommy BraasCommented:
;-D
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.