1 2 Previous Next 17 Replies Latest reply: Oct 27, 2009 9:07 AM by 843790 RSS

    Problem with flush method

    843790
      Hello, I'm new in java development, and I'm french with a student English, sorry if that I say is strange is the expressions.
      I have a problem with network streams and serialization.
      I want to establish a connection between 2 apps, on 2 different computers. For the development, the tests are local (IP : 127.0.0.1)
      The problem : I send 4 bytes and I flush after, and I receive 6 bytes. To know what is transmitting on the connection, I override the OutputStream class.
      I think that the flush() method produces 2 bytes but i don't think how.

      I put you the codes follow :
      Thanks for any help.





      The sender function :
      _____________________
      // This function is called when the user want to send data to another user.
      // This piece of function establishing the connection between 2 users.
      
      public int startListeningForNFT(String senderUserName, int indexOfSender) {
            
            System.out.println(senderUserName + " demande à " + this.userName + " de démarrer la procédure de réception.");
            
            /* Cette fonction est l'interface ente le serveur et le client2,
             * elle retourne le port  et l'IP que le client2 le lui a renvoyé. */
      
            /* This function send an Integer which will trig a reception function in the receiver
               This function is called in a Thread. */
            
            try {
               
               this.oos.writeObject(44);
               this.oos.flush();
               
               System.out.println("On a bien envoyé OBJ2AskerInfos sur le port " + portToListen);
      
               byte b = this.ois.readByte();
               System.out.println("Byte = " + b);
               b = this.ois.readByte();
               System.out.println("Byte = " + b);
               b = this.ois.readByte();
               System.out.println("Byte = " + b);
               b = this.ois.readByte();
               System.out.println("Byte = " + b);
               b = this.ois.readByte();
               System.out.println("Byte = " + b);
            }
            catch (IOException e) { e.printStackTrace(); }
            
            return Constantes.PORT_DATA;
         }
      The receiver function :
      _______________________

      public class ClientClient implements WindowClient {
      
      
         // This 3 attributes are initalized correctly.
         private Socket comSocket;
         private String comPort;
         private String userName;
      
         public ClientClient() {
      
            try {
      
            comSocket = new Socket(ipToJoin, Integer.parseInt(comPort));
            oos = new ObjectOutputStream(new DebugOutputStream(comSocket.getOutputStream()));
            ois = new ObjectInputStream(comSocket.getInputStream());
               
            oos.writeObject(userName);
            oos.flush();
      
            ThreadInputListener til = new ThreadInputListener();
            til.start();
      
            }
            catch (UnknownHostException e) { e.printStackTrace(); }
            catch (ClassNotFoundException e) { e.printStackTrace(); }
            catch (IOException e) {
               e.printStackTrace();
               JOptionPane.showMessageDialog(null, ("Auncun serveur n'a été trouvé sur l'adresse indiquée :\n" + ipToJoin), "Erreur", JOptionPane.ERROR_MESSAGE);
            }
         }
      
         public class ThreadInputListener extends Thread {
         
            @SuppressWarnings("unchecked")
            public void run() {
               try {
                  while(true) {
                     Object receivedObject = ois.readObject();
                     // Si l'objet reçu est un OBJ2InfosOnAsker => Renvoyer le port.
                     // If received Object is an integer
                     if(receivedObject instanceof Integer) {
                     
                        System.out.println(userName +" a bien reçu l'objet OBJ2InfosOnAsker...");
                        System.out.println(userName +" a bien reçu int." + receivedObject);
                     
                        System.out.println("On lance les 4 int :");
                        // Send 4 bytes to the sender (control bytes, just for solve the problem)
                        oos.writeByte(7);
                        oos.writeByte(8);
                        oos.writeByte(9);
                        oos.writeByte(10);
                        oos.flush();
                     
                        System.out.println("...et a bien envoyé le port");
                     }
                  }
               }
               catch (IOException e) {
                  // ArrayList<HostClient> temp = new ArrayList<HostClient>();
                  // temp.add(new HostFictiveClient(userName));
                  // fenetreprincipale.updateClientList(temp);
                  fenetreprincipale.addDiscution("Vous avez été déconnecté du serveur.");
               }
               catch (ClassNotFoundException e) { e.printStackTrace(); }
            }
         }
      The override function of OutputStream :
      _______________________________________
         public class DebugOutputStream extends OutputStream {
         
            private OutputStream os;
         
            public DebugOutputStream(OutputStream os) {
               super();
               this.os = os;
            }
            
            @Override
            public void write(int b) throws IOException {
               System.out.println("ClientClient envoie " + b + " soit " + ((char)b));
               os.write(b);
               
            }
         }
      }
      The sender function says :
      ______________________
      Host demande à User1 de démarrer la procédure de réception.
      On a bien envoyé OBJ2AskerInfos sur le port 3001
      Byte = 4
      Byte = 0
      Byte = 7
      Byte = 8
      Byte = 9
      And the receiver function says :
      __________________________
      User1 a bien reçu l'objet OBJ2InfosOnAsker...
      User1 a bien reçu int.44
      On lance les 7 int :
      ClientCLient envoie 119 soit w       //
      ClientCLient envoie 4 soit          // Both of this lines are stranges
      ClientCLient envoie 7 soit 
      ClientCLient envoie 8 soit 
      ClientCLient envoie 9 soit      
      ClientCLient envoie 10 soit 
      
      ...et a bien envoyé le port
        • 1. Re: Problem with flush method
          843790
          Minimus wrote:
          this.oos.writeObject(44);
          this.oos.flush();
          What makes you think that this will print 4 bytes? It's sending as an Object, not a 4-byte integer. If you want to send a 32-bit int, use DataOutputStream (I think the writeInt() method of ObjectOutputStream should work too).

          Edit I'm with you now, thought the above was the problem. I see the bytes now. Try to post less code in the future if possible.

          Edited by: endasil on 26-Oct-2009 9:38 AM
          • 2. Re: Problem with flush method
            843790
            Minimus wrote:
            byte b = this.ois.readByte();
            System.out.println("Byte = " + b);
            b = this.ois.readByte();
            System.out.println("Byte = " + b);
            b = this.ois.readByte();
            System.out.println("Byte = " + b);
            b = this.ois.readByte();
            System.out.println("Byte = " + b);
            b = this.ois.readByte();
            System.out.println("Byte = " + b);
            }
            I see you reading the bytes here, but when do you do a readObject() to read the username that you send in the constructor of ClientClient?
            • 3. Re: Problem with flush method
              843790
              Thanks for speed answer !
              Hem, The ois and oos are created before, I didn't paste the code to reduce the size of the topic.
              The userName is read before this, and it works.
              Normally, the sender send an specific object to the receiver (not a string, because of strings are directly printed in a text area) to indicate that he want to start a data communication with him. The receiver confirm that he is ready by starting an ServerSocket and sending its IP and a port to the Sender.
              After that, the sender connects to this Socket, and start a DataOuptutStream.
              This system works when my ClientClient want to send a file to the Host, but When the Host wants to send a file to the ClientClient, it doesn't works.
              Initially, when I send an Integer, I receive an ObjectStreamClass wich contains my Integer whereas, 50 cod lines before, an Integer (the index) are sended successfully...
              I don't understand anything.


              My ois and oos for the Sender function are declared like that :
                 msgSocket = ecouteur.accept();
                 oos = new ObjectOutputStream(msgSocket.getOutputStream());
                 oos.flush();
                 ois = new ObjectInputStream(msgSocket.getInputStream());
              For the code
                 this.oos.writeObject(44);
                 this.oos.flush();
              Initially, the Object writted is an specific serializable object which contains 1 String and 1 Integer. To debug my program I replace them by a simple Integer just to see if the problem source was here.

              I don't know if I'm understandable...
              • 4. Re: Problem with flush method
                843790
                Minimus wrote:
                   public class DebugOutputStream extends OutputStream {
                
                private OutputStream os;
                
                public DebugOutputStream(OutputStream os) {
                super();
                this.os = os;
                }
                
                @Override
                public void write(int b) throws IOException {
                System.out.println("ClientClient envoie " + b + " soit " + ((char)b));
                os.write(b);
                
                }
                }
                }
                This is broken. You are only delegating the write() operation (and only one write operation; there are several possibilities), but not the flush operation, etc to the underlying OutputStream. Either override and delegate all operations of OutputStream, or instead do something like this:
                public class DebugObjectOutputStream extends ObjectOutputStream {
                   //...
                   public void write(byte[] buf) {
                      super.write(buf);
                   }
                   public void write(int val) {
                      super.write(val);
                   }
                
                   //etc
                }
                And then use that class instead of an ObjectOutputStream.
                • 5. Re: Problem with flush method
                  843790
                  Minimus wrote:
                  I don't know if I'm understandable...
                  You are.
                  • 6. Re: Problem with flush method
                    843790
                    Ok, but this layer has maid just to print in the eclipse console the bytes written on the stream, With or without this function, the flush() operation generate 2 bytes, I don't know why.

                    When I want to send manually the byte '7', the result of both lines :
                       oos.writeByte(7);
                       oos.flush();
                    is that my writeByte and my flush send 3 bytes :
                    Byte val = 119 charcode = w
                    Byte val = 1 charcode =
                    Byte val = 7 charcode =
                    Only the 'Byte val = 7 charcode = ' line is good.
                    Why the flush generate 2 unknown bytes at this code position ?
                    All the others communications between Host and Client are good...

                    Thanks again for your help !
                    Minimus.
                    • 7. Re: Problem with flush method
                      843790
                      Minimus wrote:
                      Ok, but this layer has maid just to print in the eclipse console the bytes written on the stream, With or without this function, the flush() operation generate 2 bytes, I don't know why.

                      When I want to send manually the byte '7', the result of both lines :
                         oos.writeByte(7);
                      oos.flush();
                      is that my writeByte and my flush send 3 bytes :
                      Byte val = 119 charcode = w
                      Byte val = 1 charcode =
                      Byte val = 7 charcode =
                      Only the 'Byte val = 7 charcode = ' line is good.
                      Why the flush generate 2 unknown bytes at this code position ?
                      Actually, it's (might be) writing more than two bytes. Run this:
                      public class OOSTest {
                         public static void main(String[] args) throws Throwable {
                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
                            ObjectOutputStream oos = new ObjectOutputStream(baos);
                            
                            oos.writeByte(7);
                            oos.close();
                            
                            byte[] bytes = baos.toByteArray();
                            
                            System.out.println(Arrays.toString(bytes));
                            //prints "[-84, -19, 0, 5, 119, 1, 7]"
                            
                         }
                      }
                      The explanation is in the Javadoc for ObjectOutputStream:
                      Primitive data, excluding serializable fields and externalizable data, is written to the ObjectOutputStream in block-data records. A block data record is composed of a header and data. The block data header consists of a marker and the number of bytes to follow the header.
                      OOSs should only be used when the OIS is being used properly on the other end. If you don't want this header, use a DataOutputStream. Is there an actual problem or are you just confused about the extra bytes? If there is a problem in reading, my guess is that you're somehow not reading from your OIS symmetrically with your OOS. Can you post a complete, compilable example that demonstrates the behaviour? There's obviously an issue somewhere, I just haven't spotted it yet.

                      If there wasn't an actual problem in reading, well: there's your explanation.

                      Edited by: endasil on 26-Oct-2009 10:55 AM
                      • 8. Re: Problem with flush method
                        843790
                        Ok, yes I could give all the code, but there is a lot of classes, and all are needed for the program launch.
                        Are you sure you want have all this ? And if you want, I prefer send this by email.

                        I guess the original problem is that the sender and the receiver are desynchronized at a moment. I explain :
                        At a moment, a client receive an Integer, which trig the send process.
                        Also, the Integer are correctly received. Some line codes after, the process wait for a new Integer reception, and at this moment, the reception crash.
                        Instead of receive another Integer, I receive an ObjectStreamClass, I don't know why.

                        It means that the ObjectOuptutstream works correctly at the beginning, but not after a thing. But however if this is a String which is received, it works always.

                        For String and commands streams, I choose ObjectOutputStream and ObjectInputStream.

                        There is only after my problem that I try to print the bytes which are sended.
                        Thus finally, i don't want to handle headers, I just want the deserialization works like the beginning, because the writeBytes are just putted for test.

                        Thanks,
                        Minimus.
                        • 9. Re: Problem with flush method
                          843790
                          Minimus wrote:
                          Ok, yes I could give all the code, but there is a lot of classes, and all are needed for the program launch.
                          Are you sure you want have all this ? And if you want, I prefer send this by email.
                          No, I don't want all the code. I want you to strip down the code to the point where the code exhibits the problematic behaviour, and contains only the code to exhibit that behaviour. This should only be 30-40 lines at a maximum. Around here we call that an SSCCE.

                          We ask for this for two reasons. First, it gives us an example that we can use to debug, without searching through hundreds of lines of irrelevant code. Second, and most importantly, by going through the process of producing an SSCCE for us, the original poster often will discover the original problem, because they will have isolated the problematic code.

                          Without that I can't possibly help you.

                          Reply #7 has an example of an SSCCE. It contains very little code, but is runnable (after importing the classes) and demonstrates the headers produced by writeByte. You may want to take similar shortcuts; for instance, use ByteArrayOutput/InputStream so that you don't have to post the code for dealing with a socket, and so that you have given an example that is synchronous.

                          Edited by: endasil on 26-Oct-2009 11:51 AM
                          • 10. Re: Problem with flush method
                            843790
                            Ok, I'm going out of office, I back on it tomorrow, and I will see for the SSCCE.

                            Thanks, See you tomorrow,
                            Minimus.
                            • 11. Re: Problem with flush method
                              EJP
                              (a) Your stream should extend either FilterOutputStream or ObjectOutputStream.
                              (b) When you call writeObject(44) you aren't just writing the 4 bytes of an integer: you are writing an Integer object. So reading 4 bytes and expecting them to constitute the integer you sent is unwarranted. If you call writeObject() you must call readObject(); similarly for all the other methods. You have to use them symmetricaly.
                              • 12. Re: Problem with flush method
                                843790
                                Hello !
                                Well, hem I try to simplify the code to make a 'publishable' version to put here, but I have others problems, others Exceptions, other functionnality... and the code still about 160 lines.

                                @ejp :
                                I know that an writeObject(44) send an Integer Object, at the start of the problem, it's nothing more that one program do a writeObject(44), and the other program do a Obj = ois.readObject(); But at one moment, instead of received an Integer Object, I received an ObectStreamClass ! And this is this problem which bring me to simplify the transmission by writeInt and by writeByte, just to test. But finally, I want to write an Integer.
                                And the most strange in all that, that's I do well an exactly similar instruction about 30 code lines before, I write an Object with writeObject(3000) and I read an object with readObject, and it works.


                                Thanks,
                                Minimus.

                                Edited by: Minimus on Oct 27, 2009 1:44 AM

                                Edited by: Minimus on Oct 27, 2009 1:46 AM
                                • 13. Re: Problem with flush method
                                  843790
                                  Omg...

                                  I found the problem, in the global program, I have 2 Thread which try to read the ois stream, then when a data is incoming, one thread receive a part of this data and my second thread retrieve the rest of the data. I solve this problem by a Semaphore object which prevent double reading in the same time.

                                  Thanks for your help which give me the directions of my research.
                                  Minimus.
                                  • 14. Re: Problem with flush method
                                    843790
                                    Minimus wrote:
                                    I solve this problem by a Semaphore object which prevent double reading in the same time.
                                    Why do you have 2 threads reading from the same stream at all? That sounds like a recipe for disaster.
                                    1 2 Previous Next