8 Replies Latest reply: Dec 14, 2009 5:02 PM by 843790 RSS

    Client and Server throws "Invalid Type Code: AC" from socket stream

    843790
      I have found several posts on this, but none of them seem to cover what I am doing wrong on this one. I have a class that handles the IO for both the client and the server, since they both do the same thing, the communication goes like this, client sends a request to the server, server sends a PROC to identify it is processing, when done it sends an ACK to tell the client to recieve the result, then the server requests and the client does the same thing but in reverse and when they are done the client closes the connection. Since both the server and the client use the same core class for the socket and the streams, they are being opened and closed for the duration. CommPacket is the standard class for sending across the sockets. Because this application is being built modular, I need to keep the code open for adding more sections without having to modify the core code. (reason for CommPacket) At this time I only have one set of data going across, but as time goes on I will be adding classes to send. I added the in.avalible() loop to test, and found that it also was throwing the CorruptClassException when data was recieved not just with the in.readObject();
      public class CommPacket implements Serializable {
      
           private static final long serialVersionUID = 8368440663873900888L;
           public byte cmd = CommDef.NONE;
           public Object data = null;
      
           public CommPacket(byte cmd, Object data) {
                this.cmd = cmd; this.data = data;
           }
           
           public CommPacket(byte cmd) {
                this.cmd = cmd; this.data = null;
           }
      
      }
      public abstract class CommTxRx extends Thread implements CommDef {
           
           protected Socket socket = null;
          private ObjectInputStream in = null;
          private ObjectOutputStream out = null;
          private boolean streamOk = false;
      
          public CommTxRx(Socket socket) {
            this.socket = socket; 
            try {
                socket.setSoTimeout(TIMEOUT);
                socket.setReceiveBufferSize(BUFFER_SIZE);
                socket.setSendBufferSize(BUFFER_SIZE);
            } catch (SocketException e) {}
          }
          
          public void run () {
               try {
                  in = new ObjectInputStream(socket.getInputStream());
                out = new ObjectOutputStream(socket.getOutputStream());
               } catch (IOException e) {
                System.err.println("Stream Setup Error"+e.getMessage());
                streamOk = false;
                return;
               }
               streamOk = true;
               initConn(socket);
               synchronized(this) {
                  while(streamOk) { 
                    try {
                     processPacket(read());
                  } catch (IOException e) { 
                       e.printStackTrace();
                       break;
                  }          
                  } 
               }
               close();
          }
           
          public boolean up() {return streamOk;}
          
          protected CommPacket read() throws IOException {
               if (!streamOk) throw new IOException("Stream Closed!");
              CommPacket packet = null;
              while (packet==null) {
                   try {
                        synchronized(this) {
                             while(in.available() == 0) {
                                  try { wait(200); } catch (InterruptedException e) {}
                             }
                        }
                        packet = (CommPacket) in.readObject(); 
                   } catch (SocketTimeoutException e) {
                        updateStatus(ERROR, "Packet Timeout");
                        System.err.println("Packet Timeout!");
                        streamOk = false;
                        return null;
                   } catch (ClassNotFoundException e) {
                        System.err.println("Packet Read Class Error!\n"+e.getMessage());
                        updateStatus(ERROR, "Packet Read Class Error!");
                        send(RESEND);
                   } catch (InvalidClassException e) {
                        System.err.println("Packet Invalid Class Error!\n"+e.getMessage());
                        updateStatus(ERROR, "Packet Invalid Class Error!");
                        send(RESEND);
                   } catch (StreamCorruptedException e) {
                        System.err.println("Packet Corrupt Class Error!\n"+e.getMessage());
                        updateStatus(ERROR, "Packet Corrupt Class Error!");
                        send(RESEND);
                   } catch (OptionalDataException e) {
                        System.err.println("Extra Data Error!\n"+e.getMessage());
                        updateStatus(ERROR, "Extra Data Error!");
                   } catch (IOException e) {
                        updateStatus(ERROR, "IO Error");
                        System.err.println("IO Error!");
                        streamOk = false;
                        return null;          
                   }
                   if (streamOk == false) break;
              }
              send(PROC);
              return packet;
          }
          
          protected void send(byte what) throws IOException {
               if (!streamOk) throw new IOException("Stream Closed!");
               out.writeObject(new CommPacket(what)); out.flush();
               updateStatus(what, "Sending");
          }
          
            
          protected void write(CommPacket packet) throws IOException {
               if (!streamOk) throw new IOException("Stream Closed!");
               updateStatus(packet.cmd, "Writing Stream");
               out.reset();
               out.writeObject(packet);out.flush();
              CommPacket rtn = null;
               while (true) {
                    rtn = read();
                    switch (rtn.cmd) {
                      case ACK: updateStatus(rtn.cmd, "Ack Recieved"); return;
                      case PROC: updateStatus(rtn.cmd, "Processing"); break;
                      case RESEND: { updateStatus(rtn.cmd, "Resending"); 
                                          out.writeObject(packet);out.flush(); break; }
                      case ERROR: { updateStatus(rtn.cmd, "Write Ack Error"); 
                                    throw new IOException("Stream Error!");}
                    }
               }
          }
      
          
          public void close() {
               try {
                    out.close();
                } catch (IOException e) {
                     System.out.println("Stream In Close Error."+e.getMessage());
                }
                try {
                    in.close();
                } catch (IOException e) {
                     System.out.println("Stream Out Close Error."+e.getMessage());
                }
                try {
                    socket.close();
                } catch (IOException e) {
                     System.out.println("Socket Close Error."+e.getMessage());
                }
                streamOk = false;
                commDone();
          }
          
          public void abort() {
               System.err.println("Abort Connection!");
               streamOk = false;
          }
          
          protected abstract void initConn (Socket socket);
          
          protected abstract void processPacket(CommPacket packet);
          
          protected abstract void updateStatus(int status, String text);
          
          protected abstract void commDone();
      }
        • 1. Re: Client and Server throws "Invalid Type Code: AC" from socket stream
          EJP
          I have found several posts on this
          AC is the first byte written to a new ObjectOutputStream. The posts you found should all say that this error results from using a new ObjectOutputStream at the sender and an old ObjectInputStream at the receiver, after an ObjectOutputStream has already been used on the same socket. You must be doing that at the sending side. Use the same streams for the life of the socket.
                    synchronized(this) {
                         while(in.available() == 0) {
                              try { wait(200); } catch (InterruptedException e) {}
                         }
          This is a complete waste of time. Remove it. The readObject() method will block until data is available. All this does is provide an additional delay of up to 199.999ms.
          catch (SocketTimeoutException exc) {
                    streamOk = false;
          The stream is still OK, it's just that no-one has written to it lately. You don't need to treat it as dead, close it, etc.
               } catch (ClassNotFoundException e) {
                    send(RESEND);
          Resending won't fix this. It is a fatal application deployment error.
               } catch (InvalidClassException e) {
                    send(RESEND);
          Ditto.
               } catch (StreamCorruptedException e) {
                    System.err.println("Packet Corrupt Class Error!\n"+e.getMessage());
                    updateStatus(ERROR, "Packet Corrupt Class Error!");
                    send(RESEND);
          And this is fatal too. The stream is no longer OK and an application protocol implementation error is indicated.

          Again, resending won't fix any of these: all you can do is close the socket, log the error, and call support or display the developer's home phone number ;-)
          public void close() {
                    out.close();
                    in.close();
                    socket.close();
          You only need out.close(). That closes the socket and therefore the input stream.
          • 2. Re: Client and Server throws "Invalid Type Code: AC" from socket stream
            843790
            ejp wrote:
            I have found several posts on this
            AC is the first byte written to a new ObjectOutputStream. The posts you found should all say that this error results from using a new ObjectOutputStream at the sender and an old ObjectInputStream at the receiver, after an ObjectOutputStream has already been used on the same socket. You must be doing that at the sending side. Use the same streams for the life of the socket.
            I guess that is my main question, because as soon as both sockets open, I am creating the streams so I cannot understand where an old ObjectxxxStream is happening. I am using this same class for both the server and the client so I am opening the Object streams only once, unless I cannot create a ObjectInputStream and a ObjectOutputStream on the same socket.
                      synchronized(this) {
                           while(in.available() == 0) {
                                try { wait(200); } catch (InterruptedException e) {}
                           }
            This is a complete waste of time. Remove it. The readObject() method will block until data is available. All this does is provide an additional delay of up to 199.999ms.
            Actually I already did, I only put it in there so I could catch the break point when debugging. Without it the break would happen every loop because I was breaking at the read, and I wanted to break only when there was data to read.
            catch (SocketTimeoutException exc) {
                      streamOk = false;
            The stream is still OK, it's just that no-one has written to it lately. You don't need to treat it as dead, close it, etc.
            In this application I need to know that, this application will be on computers that the network connection may be interrupted so I want to know if the connection gets dropped. This is written so that there is activity at least every 15sec, if not it will assume the connection was lost and will close everything and try later when the connection becomes active again. I have other classes that take care of that. That is why my app sends a 'PROC' every 10sec. while it is processing a packet of information. I am actually a phone guy so this is written a lot like Q.931 or sip, because I am familiar with the control flow.
                 } catch (ClassNotFoundException e) {
                      send(RESEND);
            Resending won't fix this. It is a fatal application deployment error.
                 } catch (InvalidClassException e) {
                      send(RESEND);
            Ditto.
                 } catch (StreamCorruptedException e) {
                      System.err.println("Packet Corrupt Class Error!\n"+e.getMessage());
                      updateStatus(ERROR, "Packet Corrupt Class Error!");
                      send(RESEND);
            And this is fatal too. The stream is no longer OK and an application protocol implementation error is indicated.
            So any of those errors result in a invalid stream and the socket should be closed, I thought I could recover and have the other end resend the info, instead completely shut down and start over with a new socket. Got it. If the ObjectInputStream had one of these errors, could I still send on the ObjectOutputStream to tell the other side of the error and to close its socket?
            >
            Again, resending won't fix any of these: all you can do is close the socket, log the error, and call support or display the developer's home phone number ;-)
            public void close() {
                      out.close();
                      in.close();
                      socket.close();
            You only need out.close(). That closes the socket and therefore the input stream.
            I read that on another post while researching this, I just did not do it yet. I figured it did not hurt. Just wondering though, if you setup another OutputStream of some sort on the same socket, and then close it, then it closes everything, right?



            Here are the changes:
            public abstract class CommTxRx extends Thread implements CommDef {
                 
                 protected Socket socket = null;
                private ObjectInputStream in = null;
                private ObjectOutputStream out = null;
                private boolean streamOk = false;
            
                public CommTxRx(Socket socket) {
                  this.socket = socket; 
                  try {
                      socket.setSoTimeout(TIMEOUT);
                      socket.setReceiveBufferSize(BUFFER_SIZE);
                      socket.setSendBufferSize(BUFFER_SIZE);
                  } catch (SocketException e) {}
                }
                
                public void run () {
                     try {
                        in = new ObjectInputStream(socket.getInputStream());
                      out = new ObjectOutputStream(socket.getOutputStream());
                     } catch (IOException e) {
                      System.err.println("Stream Setup Error"+e.getMessage());
                      streamOk = false;
                      return;
                     }
                     streamOk = true;
                     initConn(socket);
                     synchronized(this) {
                        while(streamOk) { 
                          try {
                           processPacket(read());
                        } catch (IOException e) { 
                             e.printStackTrace();
                             break;
                        }          
                        } 
                     }
                     close();
                }
                 
                public boolean up() {return streamOk;}
                
                protected CommPacket read() throws IOException {
                     if (!streamOk) throw new IOException("Stream Closed!");
                    CommPacket packet = null;
                    while (packet==null) {
                         try {
                              packet = (CommPacket) in.readObject(); 
                         } catch (SocketTimeoutException e) {
                              updateStatus(ERROR, "Packet Timeout");
                              System.err.println("Packet Timeout!");
                              streamOk = false; return null;
                         } catch (Exception e) {
                              updateStatus(ERROR, "Fatal Error");
                              System.err.println("Fatal Error!"+"\n"+e.getMessage());
                              streamOk = false; return null;          
                         }
                         if (streamOk == false) break;
                    }
                    send(PROC);
                    return packet;
                }
                
                protected void send(byte what) throws IOException {
                     if (!streamOk) throw new IOException("Stream Closed!");
                     out.reset();
                     out.writeObject(new CommPacket(what)); out.flush();
                     updateStatus(what, "Sending");
                }
                
                  
                protected void write(CommPacket packet) throws IOException {
                     if (!streamOk) throw new IOException("Stream Closed!");
                     updateStatus(packet.cmd, "Writing Stream");
                     out.reset();
                     out.writeObject(packet);out.flush();
                    CommPacket rtn = null;
                     while (true) {
                          rtn = read();
                          switch (rtn.cmd) {
                            case ACK: updateStatus(rtn.cmd, "Ack Recieved"); return;
                            case PROC: updateStatus(rtn.cmd, "Processing"); break;
                            case RESEND: { updateStatus(rtn.cmd, "Resending"); 
                                                out.writeObject(packet);out.flush(); break; }
                            case ERROR: { updateStatus(rtn.cmd, "Write Ack Error"); 
                                          throw new IOException("Stream Error!");}
                          }
                     }
                }
            
                
                public void close() {
                     try {
                          out.close();
                      } catch (IOException e) {
                           System.out.println("Stream In Close Error."+e.getMessage());
                      }
                      streamOk = false;
                      commDone();
                }
                
                public void abort() {
                     System.err.println("Abort Connection!");
                     streamOk = false;
                }
                
                protected abstract void initConn (Socket socket);
                
                protected abstract void processPacket(CommPacket packet);
                
                protected abstract void updateStatus(int status, String text);
                
                protected abstract void commDone();
            }
            Still had the same error

            Edited by: Jeremy50 on Dec 10, 2009 12:51 AM
            • 3. Re: Client and Server throws "Invalid Type Code: AC" from socket stream
              EJP
              I guess that is my main question, because as soon as both sockets open, I am creating the streams so I cannot understand where an old ObjectxxxStream is happening.
              A new ObjectOutputStream is happening when the other end's ObjectInputStream has already read from an older one. The evidence is conclusive. AC is the first byte written when you construct one.
              If the ObjectInputStream had one of these errors, could I still send on the ObjectOutputStream to tell the other side of the error and to close its socket?
              Yes, the error only affects one direction.
              If you setup another OutputStream of some sort on the same socket, and then close it, then it closes everything, right?
              Yes. Yet another reason not to do it ;-)
              public CommTxRx(Socket socket) {
                   this.socket = socket;
                   try {
                        socket.setSoTimeout(TIMEOUT);
                        socket.setReceiveBufferSize(BUFFER_SIZE);
                        socket.setSendBufferSize(BUFFER_SIZE);
                   } catch (SocketException e) {}
              I would set up the input and output streams in here in the constructor, and I would let IOExceptions be thrown by the constructor instead of catching some of them and ignoring them. That way if you can't create the streams you can't create the object so you remove a whole level of complexiy from the subsequent code. You could even declare the streams as 'final' in the class to ensure this the only place they are being created.
                   streamOk = true;
              I don't use booleans for this sort of thing: let the exceptions do the talking.
              public boolean up() {return streamOk;}
              This is really pretty misleading. All it is telling you is that you haven't had an error yet. It doesn't mean the connection is currently 'up'. Nothing means that really in TCP/IP.
                   if (!streamOk) throw new IOException("Stream Closed!");
              Again here I would have closed the streams/sockets if there was an exception and I would let the I/O methods throw their own exceptions if called when closed. You're just adding belts to the braces.
                   out.reset();
                   out.writeObject(new CommPacket(what)); out.flush();
              You don't really need the reset here, you're writing a new packet. But it does save memory.
              public void abort() {
                   System.err.println("Abort Connection!");
                   streamOk = false;
              You should certainly make some attempt to close the output stream or at least the socket here.
              • 4. Re: Client and Server throws "Invalid Type Code: AC" from socket stream
                843790
                ejp wrote:
                I guess that is my main question, because as soon as both sockets open, I am creating the streams so I cannot understand where an old ObjectxxxStream is happening.
                A new ObjectOutputStream is happening when the other end's ObjectInputStream has already read from an older one. The evidence is conclusive. AC is the first byte written when you construct one.
                This is what I am getting hung up on, the server is in a (serverSocket.accept()).start() when the client attempts the connect, both sides then create the ObjectStreams, does what you are saying mean I can only send one object, then I have to close and re-create the streams? I thought that is what the .reset() does for the ObjectOutputStream, from what I read in the javadoc, .reset() for the ObjectInputStream does not apply here. From what you said below, I can use final to make sure the streams are not re-created, but I am not seeing where I am re-creating the streams and where I am using a new input to and old output. I'll change it to create the streams in the constructor and final them and see what happens.
                public CommTxRx(Socket socket) {
                     this.socket = socket;
                     try {
                          socket.setSoTimeout(TIMEOUT);
                          socket.setReceiveBufferSize(BUFFER_SIZE);
                          socket.setSendBufferSize(BUFFER_SIZE);
                     } catch (SocketException e) {}
                I would set up the input and output streams in here in the constructor, and I would let IOExceptions be thrown by the constructor instead of catching some of them and ignoring them. That way if you can't create the streams you can't create the object so you remove a whole level of complexiy from the subsequent code. You could even declare the streams as 'final' in the class to ensure this the only place they are being created.
                Ill make the changes, Did not think of that.
                     streamOk = true;
                I don't use booleans for this sort of thing: let the exceptions do the talking.
                The boolean is to drop the loop in the run() to terminate the thread, then it closes the socket. I thought the read would just block so the thread would hang. If just closing the out stream would cause that to happen then I would eliminate the boolean.
                public boolean up() {return streamOk;}
                This is really pretty misleading. All it is telling you is that you haven't had an error yet. It doesn't mean the connection is currently 'up'. Nothing means that really in TCP/IP.
                True, I never used it. It was a thought early on and I just forgot to remove it.
                     if (!streamOk) throw new IOException("Stream Closed!");
                Again here I would have closed the streams/sockets if there was an exception and I would let the I/O methods throw their own exceptions if called when closed. You're just adding belts to the braces.
                Ok, I'll change that. That again was a early thing that I should of removed.
                public void abort() {
                     System.err.println("Abort Connection!");
                     streamOk = false;
                You should certainly make some attempt to close the output stream or at least the socket here.
                Well, the boolean does cause the streams and socket to close, but not directly. It kills the run loop that keeps the thread alive and then it runs close(); I wanted to clean up before just dropping everything.
                • 5. Re: Client and Server throws "Invalid Type Code: AC" from socket stream
                  EJP
                  does what you are saying mean I can only send one object, then I have to close and re-create the streams?
                  No. It means precisely the opposite. Create the streams once for the life of the socket. I've said that several times, I don't know what the confusion is.
                  I wanted to clean up before just dropping everything.
                  You can't. When you get any exception other than a timeout the socket is dead. All you can do is close it so you may as well do that right away so you know it's done.
                  • 6. Re: Client and Server throws "Invalid Type Code: AC" from socket stream
                    843790
                    ejp wrote:
                    does what you are saying mean I can only send one object, then I have to close and re-create the streams?
                    No. It means precisely the opposite. Create the streams once for the life of the socket. I've said that several times, I don't know what the confusion is.
                    Yep, I found it. My error, I was creating another stream in a different class that I was not looking at. I changed that and it now no longer throws that error. I have another issue now, not related. Thank you for all your input, it has really helped, but in the end it was my stupidity.
                    I wanted to clean up before just dropping everything.
                    You can't. When you get any exception other than a timeout the socket is dead. All you can do is close it so you may as well do that right away so you know it's done.
                    I changed that, everything just throws exceptions now. If the read() throws in the main loop it breaks and lets the thread die.
                    • 7. Re: Client and Server throws "Invalid Type Code: AC" from socket stream
                      EJP
                      Good to hear it's working, thanks for the confirmation.
                      • 8. Re: Client and Server throws "Invalid Type Code: AC" from socket stream
                        843790
                        I thought I would post what my class ended up as, I believe it is working and the bugs I am working out are in other classes. My original issue was I had a separate class for the keep alive packet and it was opening another ObjectOutputStream() on the socket, I just combined it with this class instead.
                        public enum CommProtocal {
                              ACK ("ACK"),
                              PROC ("Processing"),
                              END ("End"),
                              ABORT ("Abort"),
                              ERROR ("Error");
                              
                              private final String desc; 
                              
                              private CommProtocal (String desc) {
                                   this.desc = desc;
                              }
                              
                              public String description() {return desc;}
                        }
                        public class CommPacket<T> implements Serializable {
                        
                             private static final long serialVersionUID = 8368440663873900888L;
                             private byte cmd;
                             private final T data;
                        
                             public CommPacket(byte cmd, T data) {
                                  this.cmd = cmd; this.data = data;
                             }
                             
                             public CommPacket(byte cmd) {
                                  this.cmd = cmd; this.data = null;
                             }
                             
                             public byte getCmd() {return cmd;}
                             
                             public T getData() {return data;}
                        
                        }
                        public abstract class CommTxRx extends Thread {
                             
                             private final ObjectInputStream in;
                            private final ObjectOutputStream out;
                            private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
                            private final ScheduledFuture<?> keepHandle;
                             private volatile boolean keepOn = false;
                             private volatile boolean keepLock = false; 
                             protected volatile boolean acked = false;
                             public volatile boolean isClosed = false;
                        
                            public CommTxRx(Socket socket) throws IOException {
                                 socket.setSoTimeout(CommDef.TIMEOUT);
                                  socket.setReceiveBufferSize(CommDef.BUFFER_SIZE);
                                  socket.setSendBufferSize(CommDef.BUFFER_SIZE);
                                  out = new ObjectOutputStream(socket.getOutputStream());      
                                  in = new ObjectInputStream(socket.getInputStream());
                                  keepHandle = scheduler.scheduleAtFixedRate(new KeepAlivePacket(), 
                                            CommDef.KEEPTIME, CommDef.KEEPTIME, TimeUnit.SECONDS);
                                  updateStatus("Opened Stream to: "+socket.getInetAddress().getHostName());
                            }
                            
                            public void run () {
                                 try {
                                  initConn();
                               } catch (Exception e) {
                                  abort();
                                  return;
                               } 
                                 updateStatus("Running...");
                                 synchronized(this) {
                                    while(true) { 
                                      try {
                                         CommPacket<?> packet = read();
                                       if (packet != null) {
                                            keepOn = true;
                                            processPacket(packet);
                                            keepOn = false;
                                       }
                                    } catch (Exception e) { e.printStackTrace(); break; }          
                                    } 
                                 }
                                 abort();
                            }
                             
                            protected CommPacket<?> read() throws IOException, ClassNotFoundException {
                                 if (isClosed) throw new IOException("Streams Closed!");
                                Object reader = null; 
                                while (true) {
                                  reader = in.readObject();
                                  if (reader instanceof CommProtocal) {
                                       updateStatus( "Protocal Recieved: "+ ((CommProtocal) reader).description());            
                                    switch ((CommProtocal) reader) {
                                       case PROC: break;
                                       case ERROR: { close(CommProtocal.ERROR); return null;}
                                       case ABORT: { close(CommProtocal.ABORT); return null;}
                                       case END: { close(CommProtocal.END); return null; }
                                       case ACK: { acked = true; return null; }
                                     }
                                  } else if (reader instanceof CommPacket<?>) {
                                       updateStatus( "Packet Recieved");
                                       return (CommPacket<?>) reader;
                                  }
                                }
                            }
                            
                            public void ack() throws IOException {
                                 send(CommProtocal.ACK);
                            }
                            
                            public void end() {
                                 close(CommProtocal.END);
                            }
                            
                            public void abort() {
                                 close(CommProtocal.ABORT);
                            }
                            
                            public void error() {
                                 close(CommProtocal.ERROR);
                            }
                            
                            private void send(CommProtocal what) throws IOException {
                                 waitForKeepLock();
                                 out.reset();
                                 out.writeObject(what); 
                                 out.flush();
                                 updateStatus("Sending:"+what.description());
                            }
                            
                              
                            public void write(CommPacket<?> packet) throws IOException, ClassNotFoundException {
                                 waitForKeepLock();
                                 out.reset();
                                 out.writeObject(packet);
                                 out.flush();
                                 updateStatus("Writing Packet");
                                 acked = false;
                            }
                        
                            
                            private void close(CommProtocal reason) {
                                 if (isClosed) return;
                                 keepHandle.cancel(true);
                                 try {
                                      send(reason);
                                  } catch (IOException e) {}
                                  try {
                                       out.close();
                                  } catch (IOException e) {}
                                  commDone();
                                  updateStatus("Closing:"+reason.description());
                                  isClosed = true;
                            }
                            
                            public void waitForKeepLock() {
                                 synchronized(this) {
                                      keepOn = false;
                                      while(keepLock) {
                                           try { wait(20); } catch (InterruptedException e) {}
                                      }
                                 }
                            }
                            
                            private class KeepAlivePacket extends Thread {
                                 public void run () {
                                      if (out != null && keepOn) {
                                           try {
                                                keepLock = true;
                                                send(CommProtocal.PROC); 
                                                updateStatus("KeepAlive");
                                           } catch (IOException e) { close(CommProtocal.ERROR); }; 
                                           keepLock = false;
                                      }
                                 }
                              }
                            
                            protected abstract void initConn () throws IOException, ClassNotFoundException;
                            
                            protected abstract void processPacket(CommPacket<?> packet) throws IOException, ClassNotFoundException;
                            
                            protected abstract void updateStatus(String text);
                            
                            protected abstract void commDone();
                          
                        }