2013-06-12 9 views
6

Jestem naprawdę mylić przez to: niektóre z moich kodu nie działa, gdy uruchomię mój program normalnie w Eclipse, ale robi wok kiedy biegnę przez każdy krok osobno, korzystając z trybu debugowania.kod nie działa, gdy pracuje normalnie, ale praca w debugowania (eclipse)

Kod:

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); 

} 

Łącznik (jest uruchamiany (jako gwintu) tak szybko, jak użytkownik kliknie 'connect' w oknie dialogowym):

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() powraca true tak szybko, jak jest podłączony do serwera. Złącze działa na osobnym wątku.

EDIT: Próbowałem umieścić kod w getConnected() podczas blokowania, a następnie działa. Dlaczego to działa, a nie inaczej?

+3

Może to być sytuacja wyścigowa. Czy możesz wysłać kod do 'ConnectDialog'? – austin

+0

Czy oceniasz wyrażenia podczas swoich punktów przerw? Te oceny mogą faktycznie zmienić stan twojego programu (może masz szczęście i zmieniło go w stan roboczy?) –

+0

@austin Kod ConnectDialog ma 700 linii, więc będę umieszczał kod tylko na rzeczywistym łączniku (który jest nadal bardzo długi ...) Nadzieję, że dobrze z tym. – Creator13

Odpowiedz

3

Miałem ten sam problem, ale z nieco większą specyfikacją. Kod działa dobrze na 32-bitach, ale miałem ten problem na 64-bitowej (używam biblioteki natywnej, więc muszę zachować oba).

Rozwiązaniem, które znalazłem, jest dodanie Thread.sleep() w pętli while. Nie wiem, dlaczego to działa, więc twoje przypuszczenie jest równie dobre jak moje.

Lepszym rozwiązaniem byłoby prawdopodobnie realizować Observer Pattern zamiast nieskończonej pętli. Ale to wymagałoby ponownego przeliczenia.

2

miałem bardzo podobny problem z pętli „while”, że nie stałoby i że pętla była moim głównym rutyna. Jak mam pętla do uruchomienia, że ​​pierwszą rzeczą, która została wykonana w pętli był sen:

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

To wystarczyło, aby dostać wszystko co się dzieje.

0

Korzystanie Thread.sleep(), a pozostałe odpowiedzi sugerują, powinno rozwiązać problem, ale nie jest to bardzo dobre podejście. Zamiast tego powinniśmy używać Thread.yield().

Dlaczego yield i nie sleep?

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

Dlaczego to działa?

Kiedy tylko uruchomić wątki, system operacyjny umieszcza je do „idle” stan i kiedy oczekuje się na „wake-up”, to nie. Z drugiej strony, w trybie debugowania mamy kontrolowane środowisko. System operacyjny ma nad nim niewielką kontrolę, ponieważ wszystko idzie powoli, krok po kroku. Jeśli uruchomimy debugowanie kilka razy bez żadnych punktów krytycznych, po kilku udanych uruchomieniach powinniśmy zobaczyć ten sam efekt.

Powiązane problemy