ClassCastException

0

Witam,

Aplikacja klient oraz serwer.
Gdy jeden klient podłączy się do serwera jest OK, natomiast gdy dołączę drugiego zaczyna się coś dziać dziwnego.

Dostaję komunikaty:
java.lang.ClassCastException: java.io.ObjectStreamClass cannot be cast to serwerwiadomosci.message
java.io.StreamCorruptedException: invalid type code: 00

Czy pierwszy komunikat nie mówi przypadkiem o tym, że coś co przychodzi od klienta jest nie prawidłowe?
Pogrzebałem trochę w sieci i wygląda na to, że problem może występować podczas wysyłania obiektu. Jakieś niekompatybilne typy zmiennych??

Kod serwera

package serwerwiadomosci;

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JList;
import javax.swing.JTextField;


public class SerwerWiadomosci {

    static ArrayList KlienciArrayList; // Tablica z PrintWriter klientow
    JTextField wiadomosc;
    Socket gniazdo;
    JList jListaKlientow;
    String[] tListaKlientow;
    long nrKlienta2;
    ObjectOutputStream pisarz;
    ObjectInputStream czytelnikStrm;

    
    
       
    public class ObslugaKlientow implements Runnable {
        Socket gniazdo;
        long nrk2;
       
        public ObslugaKlientow(Socket clientSocket, long nrk) throws IOException {
            
            try {
                gniazdo = clientSocket;
                nrk2 = nrk;
                
                // Obiekt czytający obiekty
                czytelnikStrm = new ObjectInputStream(gniazdo.getInputStream());
                
            } catch(Exception ex) {}
        }// koniec konstruktora
        
        @Override
        public void run(){
            try {
                while (true) {
                    message m = (message) czytelnikStrm.readObject();
                    
                    switch (m.getType()) {
                        case "p":
                            if (m.getType().contains("p")) {
                            // sprawdzam a tablicy ktory wpis ma takie gniazdo i pobieram id klienta
                            for (int i=0; i<KlienciArrayList.size(); i++) {
                                klient a = (klient) KlienciArrayList.get(i);
                                    if (a.getNrKlienta() == nrk2) {
                                        // tutaj kod zmieniajacy timestamp dla klienta
                                        a.setTime(System.currentTimeMillis());
                                        String kontrolny = m.getMessage();
                                        a.setHostName(kontrolny);
                                    }
                            }
                            System.out.println("odebralem pakiet kontrolny od klienta nr: " + nrk2);
                            // Tutaj kod informujacy klienta o stanie polaczenia z serwerem.
                            message x = new message("p","", false);
                            x.setNrKlienta(nrk2);
                            pisarz.writeObject(x);
                            }
                            break;
                            
                        case "m":
                            System.out.println("Odczytano wiadomość od klienta: " + m.getMessage());
                            InetSocketAddress remoteAddr = (InetSocketAddress)gniazdo.getRemoteSocketAddress();
                            String remoteAddrId = remoteAddr.getHostName();
                            MainForm.odebraneWiadomosci.setText(MainForm.odebraneWiadomosci.getText() + "Klient (" + remoteAddrId + ") pisze: " + m.getMessage() + "\n");
                            
                            // Automatyczne skrolowanie tresci
                            MainForm.odebraneWiadomosci.setCaretPosition(MainForm.odebraneWiadomosci.getDocument().getLength());
                            break;
                        case "ok":
                                for (int i=0; i<KlienciArrayList.size(); i++) {
                                    klient a = (klient) KlienciArrayList.get(i);
                                    if (a.getNrKlienta() == nrk2) {
                                            System.out.println("Klient: " + a.getHostName() + " nacisnął OK");
                                            MainForm.odebraneWiadomosci.setText(MainForm.odebraneWiadomosci.getText() + "Klient (" + a.getHostName() + ") potwiedził odczytanie wiadomości. \n");
                                    }
                            }
                            
                            break;
                            
                        default:  
                    }
                    
                }// koniec while
            } catch (Exception ex) {
            // W razie rozłączenia piszemy stosowny komunikat
                ex.printStackTrace();
            MainForm.odebraneWiadomosci.setText(MainForm.odebraneWiadomosci.getText() + "Klient się odłączył... \n");            
            }
            
            
        } // koniec metody run()
    } // koniec klasy wewnetrznej

    
    public static void main(String[] args) {
        
        SerwerWiadomosci gui = new SerwerWiadomosci();
        gui.doRoboty();
       
    }
public void doRoboty() {
    // Interfejs GUI jako wątek 
    
    Thread g = new Thread(new TworzGui());
    Thread s = new Thread(new SprawdzKlientow());
    g.start();
    s.start();
     
    // Tworzenie gniazda nasłuchu
    
    KlienciArrayList = new ArrayList();
    try {
        ServerSocket serverSock = new ServerSocket(5000); //gniazdo nasłuchu
        
        //Pętla nieskonczona w której odbierane są polaczenia
        while(true) {
            Socket gniazdoKlienta = serverSock.accept();
            pisarz = new ObjectOutputStream(gniazdoKlienta.getOutputStream());
            
            InetSocketAddress remoteAddr = (InetSocketAddress)gniazdoKlienta.getRemoteSocketAddress();
            String remoteAddrId = remoteAddr.getHostName();
            nrKlienta2 = System.currentTimeMillis();
            klient k = new klient(pisarz,remoteAddrId,System.currentTimeMillis(), nrKlienta2, gniazdoKlienta);
            KlienciArrayList.add(k);
            Thread t = new Thread(new ObslugaKlientow(gniazdoKlienta,nrKlienta2));
            t.start();
            System.out.println("Klient uzyskał numer: " + nrKlienta2);
            System.out.println("Mamy połączenie");

            MainForm.odebraneWiadomosci.setText(MainForm.odebraneWiadomosci.getText() + "Nowy klient o adresie " + remoteAddrId + " się podłączył \n");
            // Aktualizacja listy klientow w GUI na podstawie Listy KlienciArrayList
            // Podczas podłączania się nowego klienta
                MainForm.model.clear();
                
                try {
                    Thread.sleep(500);
                } catch (InterruptedException exx) {
                }
                
                for (int i=0;i<KlienciArrayList.size(); i++) {
                    klient o1 = (klient) KlienciArrayList.get(i);
                    MainForm.model.addElement(o1.getHostName()); 
                }
        }
        
    } catch (Exception ex) { ex.printStackTrace();
    }
    
   
}

    public class TworzGui implements Runnable {
        
        
        @Override
        public void run() {
         // Tworzenie GUI
             MainForm m = new MainForm();
             m.setVisible(true); 

        }
    }
    
    public class SprawdzKlientow implements Runnable {
        
        //public SprawdzKlientow(ArrayList lista) {
            
        //}
        @Override
        public void run() {
            System.out.println("Odpalił się wątek sprawdzania klientów");
            while(true) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException exx) {
                }
                for (int y=0; y<KlienciArrayList.size();y++) {
                            klient b1 = (klient) KlienciArrayList.get(y);
                            // test
                            // System.out.println("klient nr: " + y + " " + b1.getHostName());
                            long Ktime = b1.getTime();
                            long Atime = System.currentTimeMillis();        
                            long LastTime = Atime - Ktime;
                            // jezeli roznica wynosi wiecej niz 30s usowamy klienta z listy
                            if (LastTime > 10000) {
                                //System.out.println("Usunac");
                                System.out.println("Odłączamklienta");
                                KlienciArrayList.remove(y);
                                // listModel.remove(y);
                                MainForm.odebraneWiadomosci.append("Odłączyłem klienta: " + b1.getAddr() + "z powodu braku kontaktu." );
                                // aktualizacja listy podlaczonych klientow w gui
                                        Iterator it = KlienciArrayList.iterator();
                                        MainForm.model.clear();
                                            while(it.hasNext()) {
                                                try {
                                                    klient k = (klient) it.next();            
                                                    MainForm.model.addElement(k.getHostName());
                                                } catch (Exception ex) {
                                                }
                                            }
                            }
                }
            }
        }
    }
}

class klient {
    ObjectOutputStream os;
    PrintWriter pw; 
    String addr;
    long time;
    Socket g;
    long nrKlienta;
    String host;
    
    public klient(ObjectOutputStream Os, String Addr, long Time, long nrk, Socket G ) {
        // pw = Pw;
        os = Os;
        addr = Addr;
        time = Time;
        nrKlienta = nrk;
        g = G;
    }
    
    public void setPrintWriter(PrintWriter Pw) {
        pw = Pw;
    }
    public void setObjectOutputStream(ObjectOutputStream Os) {
        os = Os;
    }    
    public void setAddr(String Addr) {
        addr = Addr;
    }
    public void setTime(long Time) {
        time = Time;
    }
    public void setHostName(String Host) {
        host = Host;
    }
    
    public PrintWriter getPrintWriter() {
        return pw;
    }
    public ObjectOutputStream getObjectOutputStream() {
        return os;
    }
    
    public String getAddr() {
        return addr;
    }
    
    public Long getTime() {
        return time;
    }
    public long getNrKlienta() {
        return nrKlienta;
    }
    public Socket getKlientSocket() {
        return g;
    }
    public String getHostName() {
        return host;
    }
}

Kod Klienta

package serwerwiadomosci;

import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;


public class KlientWiadomosci {

  JTextArea odebraneWiadomosci;
  JTextField wiadomosc;
  public static long NrKlienta;
  public static BufferedReader czytelnik;
  Socket gniazdo;
  String AdresSerwera = "192.168.0.13";
  String MojaNazwa;
  ArrayList<String[]> as;
  JFrame ramka;
  ObjectInputStream czytelnikStrm;
  public static ObjectOutputStream pisarzStrm;
  long SerwerTimeStamp;

  public static void main(String[] args) {
    KlientWiadomosci klient = new KlientWiadomosci();
    klient.doDziela();
  }

  public void doDziela() {
 
        try {
        File opcjePlik = new File("Settings.txt");
        FileReader czytelnikF = new FileReader(opcjePlik);
            try (BufferedReader bf = new BufferedReader(czytelnikF)) {
                String wiersz;
                
                while ((wiersz = bf.readLine()) != null) {
                    as = new ArrayList<>();
                    String[] sa = new String[1];
                    sa = wiersz.split("=");
                    as.add(sa);
                }
            }
    } catch (Exception zd) {
    } 
        
    // utworzenie graficznego interfejsu uzytkownika
    ramka = new JFrame("Klient");
    JPanel panelGlowny = new JPanel();

    odebraneWiadomosci = new JTextArea(15,35);
    odebraneWiadomosci.setLineWrap(true);
    odebraneWiadomosci.setWrapStyleWord(true);
    odebraneWiadomosci.setEditable(false);

    JScrollPane przewijanie = new JScrollPane(odebraneWiadomosci);
    przewijanie.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    przewijanie.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

    wiadomosc = new JTextField(20);

    JButton przyciskWyslij = new JButton("Wyślij");
    przyciskWyslij.addActionListener(new PrzyciskWyslijListener());


    panelGlowny.add(przewijanie);
    panelGlowny.add(wiadomosc);
    panelGlowny.add(przyciskWyslij);

    ramka.getContentPane().add(BorderLayout.CENTER, panelGlowny);
    ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    ramka.setSize(440,330);
    ramka.setVisible(true);
    
    konfigurujKomunikacje();
    Thread watekOdbiorcy = new Thread(new OdbiorcaKomunikatow());
    watekOdbiorcy.start();
  } // koniec metody

  private void konfigurujKomunikacje() {
      boolean reconnect = true;
    
      while(reconnect){
        try {

        String[] AdresSerwera2 = as.get(0);
        if (AdresSerwera2[0].equals("AdresSerwera")) {
            AdresSerwera = AdresSerwera2[1];
        }    
        gniazdo = new Socket(AdresSerwera, 5000);
        czytelnikStrm = new ObjectInputStream(gniazdo.getInputStream());
        pisarzStrm = new ObjectOutputStream(gniazdo.getOutputStream());
        
        reconnect = false;
        System.out.println("Obsługa sieci gotowa!");
        ramka.setTitle("Podłączony do serwera");
        
        // Wysyłam informację z nazwą hosta i pingpong
        InetAddress remoteAddr = (InetAddress)gniazdo.getLocalAddress();
        String remoteAddrId = InetAddress.getLocalHost().getHostName();
        
        message m3 = new message("p",remoteAddrId, false);
        pisarzStrm.writeObject(m3);

      } catch(IOException ex) {
        ex.printStackTrace();
        System.out.println("Nie mogę się połącyć!!!");
        odebraneWiadomosci.append("Nie mogę się połącyć!!! \n");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException exx) {
        }
        System.out.println("Próbuję nawiązać połączenie ponownie!!!");
        odebraneWiadomosci.append("Próbuję nawiązać połączenie ponownie!!! \n");
        reconnect = true;
      }
    }// end while
    
    // Informowanie serwera o połączeniu
      Thread f = new Thread(new HeartBeat());
      f.start();
   
  } // koniec metody
  
  public class HeartBeat implements Runnable {
      
      @Override
      public void run() {
        try {
            while(true) {
                
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException exx) {
                    exx.printStackTrace();
                }
                String remoteAddrId;
                remoteAddrId = InetAddress.getLocalHost().getHostName();
                message m2 = new message("p", remoteAddrId, false);
                pisarzStrm.writeObject(m2);
                
                // sprawdzanie TimeStamp czy serwer żyje
                if ((System.currentTimeMillis() - SerwerTimeStamp) > 10000) {
                    System.out.println("Serwer umarł!!! " + (System.currentTimeMillis() - SerwerTimeStamp) );
                }
            }

        } catch (Exception ex) { ex.printStackTrace();
        }  
      }
  }
   
  public class PrzyciskWyslijListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent ev) {
      try {
         message m = new message("m", wiadomosc.getText(), false);
         pisarzStrm.writeObject(m);

      } catch(Exception ex) { ex.printStackTrace();
      }
      odebraneWiadomosci.append("Ja: " + wiadomosc.getText()+"\n");
      wiadomosc.setText("");
      wiadomosc.requestFocus();
    }
  }  // koniec klasy

  public class OdbiorcaKomunikatow implements Runnable {
    @Override
    public void run() {
      while(true) {
        try {
          message m = (message) czytelnikStrm.readObject();
          // kod sprawdzający jakiego typu wiadomość.
          // W zależności od tego wyświetlam wiadomość od administratora
          // lub jest to wiadomość kontrolna
          
          switch (m.getType()) {
              case "p":
                  System.out.println("odebrałem wiadomość kontrolną");
                  SerwerTimeStamp = System.currentTimeMillis();
                  NrKlienta = m.GetNrKlienta();
                  break;
              case "pr":
                  System.out.println("Odpalić program: " + m.getProgram());
                  Runtime.getRuntime().exec("cmd /c start " + m.getProgram());                  
                  break;
              
              default:
                  System.out.println("Odczytano: " + m.getMessage());
                  odebraneWiadomosci.append("Administrator: " + m.getMessage() + "\n");
                  if (m.getPopup() == true) {
                        Okno msgbox = new Okno();
                        msgbox.setVisible(true);
                        Okno.msg.setText("<html>" + m.getMessage() + "</html>");
                  }   
          }
                  
            
      } catch (java.io.EOFException ex) {
            System.err.println("Problem z połaczeniem");
            konfigurujKomunikacje();
            
      } catch (java.net.SocketException ex) {
            System.err.println("Problem z połaczeniem");
            konfigurujKomunikacje();        
      }   catch (IOException ex) {
              Logger.getLogger(KlientWiadomosci.class.getName()).log(Level.SEVERE, null, ex);
          } catch (ClassNotFoundException ex) {
              Logger.getLogger(KlientWiadomosci.class.getName()).log(Level.SEVERE, null, ex);
          } catch (Exception ex) {
              Logger.getLogger(KlientWiadomosci.class.getName()).log(Level.SEVERE, null, ex);
          }
      }//end while
    } // konie metody run()
  } // koniec klasy 
  
}

class message implements Serializable {
    String mes;
    boolean popup;
    String typ; // p - kontrolny, m - wiadomosc
    String program;
    long NrKlienta;
    
    // konstruktor
    public message(String t, String w, boolean p) {
        typ = t;
        mes = w;
        popup = p;
    }
    
    public String getMessage() {
        return mes;
    }
    
    public String getType() {
        return typ;
    }
    
    public void setMessage(String m) {
        mes = m;
    }
    public void setNrKlienta(Long n) {
        NrKlienta = n;
    }
    
    public Long GetNrKlienta() {
        return NrKlienta;
    }
    
    public boolean getPopup() {
        return popup;
    }
    public void setPopup(boolean p) {
        popup = p;
    }
    public void setProgram(String pr) {
        program = pr;
    }
    public String getProgram() {
        return program;
    }    
}

class Exec {
    static String WIN_PROGRAMFILES = System.getenv("programfiles");
    static String FILE_SEPARATOR   = System.getProperty("file.separator");

    public void go() throws Exception {
     String[] commands =
       {"cmd.exe",
        "/c",
        WIN_PROGRAMFILES
        + FILE_SEPARATOR
        + "Internet Explorer"
        + FILE_SEPARATOR + "iexplore www.wp.pl"};
        Process exec;
        exec = Runtime.getRuntime().exec(commands);
    }
}
0

Wstaw więcej kodu, to na bank pomoże. Zapnij sie debugerem i zobacz co się dzieje.
A za puste bloki catch powinni ci zakazać używania komputera...

0

W przypadku serwera mam jeszcze tylko klasę odpowiedzialną za tworzenie interfejsu użytkownika moim zdaniem nie bierze ona udziału na tym etapie komunikacji gdzie występuje problem. W przypadku klienta mam dodatkowo klasę, która wyświetla okienko z informacją, także nie bierze udziału na tym etapie. Wszystko to co jest źle jest zawarte w kodzie który dałem. Co do debugera nie mam zielonego pojęcia jak z niego korzystać - chętnie posłucham jakiś zaleceń jak go użyć.

Tak wygląda cała informacja jaką dostaję w wyniku błędu.

java.lang.ClassCastException: java.io.ObjectStreamClass cannot be cast to serwerwiadomosci.message
	at serwerwiadomosci.SerwerWiadomosci$ObslugaKlientow.run(SerwerWiadomosci.java:45)
	at java.lang.Thread.run(Thread.java:722)
java.io.StreamCorruptedException: invalid type code: 00
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1375)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
	at serwerwiadomosci.SerwerWiadomosci$ObslugaKlientow.run(SerwerWiadomosci.java:45)
	at java.lang.Thread.run(Thread.java:722)

Czy można włączyć jakoś aby linie w kodzie się tutaj numerowały?

0
  1. Z tym kodem żartowałem. Wstawiłeś go za dużo!
  2. To czas najwyższy się nauczyć używać debugera. Wstaw breakpoint przed miejscem gdzie leci wyjątek a potem patrz na wartości zmiennych.
0

Koleś ma podobny problem: http://stackoverflow.com/questions/706592/java-streamcorruptedexception

Ogólnie dla każdego klienta powinieneś robić osobne strumienie, robisz tak?

0

Też mi chodziło po głowie, że może to mieć z wiązek ze "złymi" strumieniami. Po analizie okazało się, że tutaj właśnie tkwił problem. Poprawiłem nieco kod i teraz jest OK.

1 użytkowników online, w tym zalogowanych: 0, gości: 1