2013-06-12 10 views
6

Ich bin wirklich verwirrt durch: einige meiner Code funktioniert nicht, wenn ich mein Programm normal in Eclipse ausführen, aber es Wok, wenn ich durch jeden laufen Schritt für Schritt mit dem Debug-Modus.Code funktioniert nicht, wenn normal ausgeführt, aber in debug (Eclipse)

Code:

public void showConnectDialog() { 
    ConnectDialog connectDialog = new ConnectDialog(); 
    connectDialog.setVisible(true); 
    //Until here, code runs 
    while(! connectDialog.getConnected()) {}; 
    //The next line does only run in debug 
    JOptionPane.showMessageDialog(connectDialog, "Connected", "Connected", JOptionPane.INFORMATION_MESSAGE); 

} 

Der Stecker (gestartet wird (wie ein roter Faden), sobald der Benutzer Hits 'connect' im Dialog):

private class ServerConnector implements ActionListener, Runnable { 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (! IP_field.getText().equals("")) { 
      if (! isConnecting) { 
       new Thread(new ServerConnector(), "ServerConnector").start(); 

      } 

     } 
     else { 
      JOptionPane.showMessageDialog(dialog, 
              "Enter an IP address", 
              "Enter IP", 
              JOptionPane.WARNING_MESSAGE); 

     } 

    } 

    @Override 
    public void run() { 
     try { 
      setConnecting(true); 
      Socket socket = connect(); 
      if (socket != null) { 
       ObjectOutputStream oOut = new ObjectOutputStream(socket.getOutputStream()); 
       ObjectInputStream oIn = new ObjectInputStream(socket.getInputStream()); 
       if (login(oOut, oIn)) { 
        isConnected = true; 
        setConnecting(false); 

       } 
       else { 
        socket.close(); 

       } 

       setConnecting(false); 

      } 

     } 
     catch (RSPException e) { 
      e.printStackTrace(); 
      System.exit(1); 

     } 
     catch (Exception e) { 
      //If an exception occurs, setConnecting() will be true. This 
      //not good, so it has to be set to false 
      e.printStackTrace(); 
      setConnecting(false); 

     } 

    } 

    private boolean login(ObjectOutputStream oOut, ObjectInputStream oIn) 
      throws ClassNotFoundException, IOException, RSPException { 
     //Send login request action: 
     oOut.writeObject(new LoginAction(ActionSender.CLIENT, getID(), 
             getPassword())); 

     Object obj = oIn.readObject(); 
     if (obj instanceof LoginActionResult) { 
      LoginActionResult result = (LoginActionResult) obj; 
      if (result.getResult() == LoginResults.SUCCES) { 
       return true; 

      } 
      else if (result.getResult() == LoginResults.FAIL_ON_ID) { 
       JOptionPane.showMessageDialog(dialog, 
               "Invalid password or ID", 
               "Can't login", 
               JOptionPane.ERROR_MESSAGE); 
       return false; 

      } 
      else if (result.getResult() == LoginResults.FAIL_ON_PASSWORD) { 
       JOptionPane.showMessageDialog(dialog, 
               "Invalid password or ID", 
               "Can't login", 
               JOptionPane.ERROR_MESSAGE); 
       return false; 

      } 
      else if (result.getResult() == LoginResults.SERVER_FULL) { 
       JOptionPane.showMessageDialog(dialog, 
               "Couldn't connect: \n" + 
               "Server is full", 
               "Failed to connect", 
               JOptionPane.WARNING_MESSAGE); 
       return false; 

      } 
      else { 
       return false; 

      } 

     } 
     else { 
      System.out.println(obj); 
      throw new RSPException("Server is not following the protocol."); 

     } 

    } 

    private void setConnecting(boolean connecting) { 
     if (connecting) { 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        connectButton.setEnabled(false); 

       } 
      }); 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        connectButton.setText("Connecting..."); 

       } 
      }); 

     } 
     else { 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        connectButton.setText("Connect"); 

       } 
      }); 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        connectButton.setEnabled(true); 

       } 
      }); 

     } 

     isConnecting = connecting; 

    } 

    private String getAddressFromTextField() { 
     return IP_field.getText(); 

    } 

    private InetAddress getInetAddress(String fullAddress) { 
     try { 
      if (fullAddress.contains(":")) { 
       String[] splitAddress = fullAddress.split(":"); 
       return InetAddress.getByName(splitAddress[0]); 

      } 
      else { 
       return InetAddress.getByName(fullAddress); 

      } 
     } 
     catch (UnknownHostException e) { 
      return null; 

     } 

    } 

    private int getPort(String fullAddress) { 
     try { 
      String[] splittedAddress = fullAddress.split(":"); 
      return Integer.valueOf(splittedAddress[1]); 

     } 
     catch (NumberFormatException ex) { 
      return -1; 

     } 
     catch (NullPointerException 
      | ArrayIndexOutOfBoundsException 
      | PatternSyntaxException ex) { 
      //Returning default port value: 25566, because no port was given 
      return 25566; 

     } 

    } 

    @SuppressWarnings("resource") 
    private Socket connect() { 
     Socket socket = null; 

     InetAddress address = null; 
     if ((address = getInetAddress(getAddressFromTextField())) == null) { 
      return null; 

     } 
     int port = getPort(getAddressFromTextField()); 

     try { 
      socket = new Socket(address, port); 

     } 
     catch (ConnectException e) { 
      Socket retrySocket = null; 
      if ((retrySocket = retryConnect(address, port)) == null) { 
       JOptionPane.showMessageDialog(dialog, 
               "Connection timed out", 
               "Failed to connect", 
               JOptionPane.ERROR_MESSAGE); 
       setConnecting(false); 

      } 
      else { 
       socket = retrySocket; 

      } 

     } 
     catch(IOException e) { 
      e.printStackTrace(); 

     } 

     return socket; 

    } 

    private Socket retryConnect(InetAddress address, int port) { 
     Thread waitThread = new Thread(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        //Will wait 15(000) (milli)seconds before stopping with 
        //trying to connect. 
        //One second (1000 millis) is for debugging and testing 
        Thread.sleep(1000); 

       } 
       catch (InterruptedException e) { 
        e.printStackTrace(); 

       } 

      } 

     }); 

     waitThread.start(); 

     while (waitThread.isAlive()) { 
      try { 
       return new Socket(address, port); 

      } 
      catch (ConnectException e) { 
       //Do nothing, will re-attempt to connect. 

      } 
      catch (IOException e) { 
       e.printStackTrace(); 

      } 

     } 

     return null; 

    } 

    private String getID() { 
     return ID_field.getText(); 

    } 

    private String getPassword() { 
     if (getID().equals("master")) { 
      return "masterPassword"; 

     } 
     else { 
      return new String(passwordField.getPassword()); 

     } 

    } 

} 

getConnected() kehrt true sobald Es ist mit dem Server verbunden. Der Connector läuft auf einem separaten Thread.

BEARBEITEN: Ich habe versucht, Code in die getConnected() während blockieren, und dann funktioniert es. Warum funktioniert es dann und nicht anders?

+3

Könnte eine Race-Bedingung sein. Können Sie den Code auf 'ConnectDialog' veröffentlichen? – austin

+0

Bewerten Sie Ausdrücke während Ihrer Unterbrechungspunkte? Diese Auswertungen können tatsächlich den Status Ihres Programms ändern (vielleicht haben Sie Glück gehabt und es in einen funktionierenden Zustand verwandelt?) –

+0

@austin Der ConnectDialog Code ist 700 Zeilen lang, also poste ich nur den Code auf den tatsächlichen Connector (welcher ist immer noch sehr lang ...) Hoffe, dass es dir gut geht. – Creator13

Antwort

3

Ich hatte das gleiche Problem, aber mit etwas mehr Spezifikation. Der Code funktionierte gut in 32bit, aber ich hatte dieses Problem in 64bit (ich benutze native Bibliothek, so dass ich beide beibehalten muss).

Die Lösung, die ich gefunden habe, ist Thread.sleep() in der While-Schleife hinzuzufügen. Ich weiß nicht, warum es funktioniert, also ist deine Schätzung so gut wie meine.

Eine bessere Lösung wäre wahrscheinlich eine Observer Pattern anstelle einer Endlosschleife zu implementieren. Aber das würde ein Re-Factoring erfordern.

2

Ich hatte ein sehr ähnliches Problem mit einer "while" -Schleife, die nicht laufen würde und diese Schleife war meine Hauptroutine. Wie ich bekam, war die Schleife zu laufen, dass die erste Sache, die in der Schleife ein Schlaf war getan wurde:

try 
     {Thread.sleep(0);} 
    catch (Exception e) 
     {e.printStackTrace();} 

, um alles geht Das war genug.

0

Mit Thread.sleep(), wie die anderen Antworten vorgeschlagen haben, sollte das Problem lösen, aber es ist kein sehr guter Ansatz. Stattdessen sollten wir Thread.yield() verwenden.

Warum yield und nicht sleep?

Siehe: Difference between Thread.Sleep(0) and Thread.Yield() und Are Thread.sleep(0) and Thread.yield() statements equivalent?

Warum das funktioniert?

Wenn wir nur die Threads ausführen, versetzt das Betriebssystem sie in den "Leerlauf" -Zustand, und wenn es erwartet wird, dass es "aufwacht", tut es das nicht. Auf der anderen Seite haben wir im Debug-Modus eine kontrollierte Umgebung. Das Betriebssystem hat wenig Kontrolle darüber, da alles langsam und schrittweise abläuft. Wenn wir das Debug einige Male ohne Break-Punkte ausführen, sollten wir nach ein paar erfolgreichen Läufen den gleichen Effekt sehen.

Verwandte Themen