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