Serializacja i socket'y

0

Witam,

Mam problem z przesyłaniem serializowanych danych między klientem i serwerem.
Ważne jest dla mnie, żeby plik serwera i klienta był w osobnych paczkach (korzystam z Netbeansa), ma to imitować sytuacje, w której klient jest oczywiście na innym komputerze niż serwer. W obu paczkach poza klasami głównymi są identyczne klasy "Pakiet".
Niestety po przesłaniu zserializowanych danych na serwer dostaję komunikat: Exception in thread "main" java.lang.ClassCastException: klient.Pakiet cannot be cast to serwer.Pakiet at serwer.serwer.main
Ale gdy umieszczę klasę serwera i klienta w jednej paczce, przesłanie danych odbywa się prawidłowo...

kody:

import java.io.*;
import java.net.*;

public class serwer {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Socket s = null;
        ServerSocket ss = null;
        
        ss = new ServerSocket(6000);
        if (ss != null)
            System.out.println("Serwer uruchomiony.");

        while (true) {
            s = ss.accept();

            if (s != null) {
                System.out.println("Nowe połączenie.");
                ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

                Pakiet p = (Pakiet) ois.readObject();

                System.out.println(p.imie +" "+p.nazwisko);
            }
        }
    }
}
import java.io.*;
import java.net.*;

public class klient {
    public static void main(String[] args) throws UnknownHostException, IOException {
        Socket s = null;

        s = new Socket("localhost", 6000);
        if (s != null) {
            System.out.println("Polaczyles sie serwerem.");
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());

            Pakiet p = new Pakiet();
            p.imie = "jan";
            p.nazwisko = "kowalski";
            
            oos.writeObject(pdw);
        }
    }
}
import java.io.Serializable;

public class Pakiet implements Serializable {
    String imie = null;
    String nazwisko = null;
}

Ostatni kod Pakietu umieszczam oczywiście zarówno w paczce serwera jak i klienta...

0

Umiesc klase Pakiet w osobnym jarze, ktor bedzie i na kliencie i na serwerze. Wzdlednie zapakuj ja do takich samych pakietow - inny pakiet oznacza inna klase, a Ty masz wlasnie 2 pakiety. common.Pakiet czy cos podobnego zda egzamin.

0

Ale co mi da osobna paczka common dla klasy Pakiet? (bo tak zrozumiałem, że mam zrobić) będzie musiała być i na komputerze gdzie jest uruchomiony serwer i na komputerze gdzie jest klient... ta sama sytuacja...

Sprawdziłem w sieci LAN na dwóch komputerach... oto wynik na serwerze:

Exception in thread "main" java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at java.net.SocketInputStream.read(SocketInputStream.java:182)
at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2249)
at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2542)
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2552)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1297)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at serwer.serwer.main(serwer.java:32)
Java Result: 1

0

Da to ze jest kompilowana raz, i wspolny kod jest w jednym miejscu - jak cos poprawisz to tylko tam, a nie w 2 pakietach. Ok, 2 paczki to niewiele, ale ucz sie dobrych zachowan juz na poczatku.
Ten blad to nie wiem skad wziales, nie wiem co zrobiles ze dostales taki wyjatek ani nic.
Natomiast powiadam Ci, ze obiekty klas z 2 roznych pakietow, nawet jesli klasy sa identyczne co do bajta, nigdy nie moga byc rzutowane na siebie wzajemnie. Ba, zdarza sie nawet ze obiekty klasy z tego samego pakietu nie moga byc na siebie rzutowane jesli klasy byly wczytane innymi classloaderami.

0

oczywiście masz racje z rzutowaniem dwóch pozornie identycznych klas.

jasne, że osobna paczka dla klasy Pakiet w przypadku uruchomienia serwera i klienta na jednym komputerze rozwiąże problem.

Natomiast w.w wyjątek został wygenerowany w ten sposób:

Na komputerze A uruchomiłem serwer, który nasłuchuje. na komputerze B (oba w tej samej sieci) uruchomiłem klienta. Wiadomo, że obie klasy muszą mieć dostęp do klasy Pakiet.

Klasa klienta połączyła się z serwerem, stworzyła obiekt klasy Pakiet, wypełniła go danymi (jan kowalski - czyt. kod wyżej) i wysłała.

no i serwer po tym jak akceptował połączenie od klienta, wyrzucił ten wyjątek.

Gdy serwer i klient korzystają z tej samej klasy Pakiet - wszystko gra.

Inaczej rzutowanie i przesłanie takiego pakietu nie działa - i o to właśnie pytam: Jak rozwiązać ten problem?

0

connection reset to nie class cast exception, tu chodzi o cos zupelnie innego. Np nie mozesz sie polaczyc z serwerem bo bolkuje firewall czy cos. Nie myl wyjatkow.
Zbudowanie servera, klienta i paczki pakiet, dodanie paczki pakiet do classpath klienta i serwera i takie przesylanie zadziala. Mozesz to zasymulowac na swoim kompie: po prostu skopiuj paczke pakiet do osobych katalogow, do nich tez skopiuj klient i serwera odpowiednio, i nastepnie uruchom serwera z classpath wskazujacym na server.jar i pakiet.jar. To samo dla klienta - powinno dzialac.

0

W sumie obstawiam ze masz jakis wyjatek na kliencie, bo taki wyjatek wlasnie jest powodowany gdy jeden z koncow komunikacji za predka zostanie zamkniety. Zauwaz ze blad masz podczas wczytywania SocketInputStream.read, czyli nawet nie doszlo jeszcze do deserializacji, wywala sie na bajtach.

0

no firewall na pewno nie jest problemem, jednak może zbyt szybko zamknięta komunikacja jest dobrym tropem? gdyby tak zastopować serwer na chwile po odebraniu strumienia?

natomiast klient nie zgłasza żadnego wyjątku

EDIT:
gdy umieściłem pliki w osobnych katalogach, tak jak pisałeś (ale bez wstrzymywania serwera jeszcze), to wyjątek na serwerze jest taki:
Exception in thread "main" java.lang.ClassCastException: klient.Pakiet cannot be cast to serwer.Pakiet
at serwer.serwer.main(serwer.java:31)
Java Result: 1

EDIT2:
gdy dodałem Thread.sleep(500); to wyjątek na serwerze:
Exception in thread "main" java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at java.net.SocketInputStream.read(SocketInputStream.java:182)
at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2249)
at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2542)
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2552)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1297)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at serwer.serwer.main(serwer.java:32)
Java Result: 1

a gdy zwiększyłem wartość sleep to znowu jest wyjątek ClassCastException na serwerze.

Generalnie kod wygląda teraz tak:

Serwer:

package serwer;

import java.io.*;
import java.net.*;

public class serwer {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        Socket s = null;
        ServerSocket ss = null;
        
        ss = new ServerSocket(6000);
        if (ss != null)
            System.out.println("Serwer uruchomiony.");

        while (true) {
            s = ss.accept();
            Thread.sleep(500);
            if (s != null) {
                System.out.println("Nowe połączenie.");
                ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
                Thread.sleep(1000);

                Pakiet pdo = (Pakiet) ois.readObject();

                System.out.println(pdo.imie +" "+pdo.nazwisko);
            }
        }
    }
}

Klient:

package klient;

import java.io.*;
import java.net.*;

public class klient {
    public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {
        Socket s = null;

        s = new Socket("localhost", 6000);
        Thread.sleep(600);
        
        if (s != null) {
            System.out.println("Polaczyles sie z serwerem.");
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
            Thread.sleep(1000);

            Pakiet p = new Pakiet();
            p.imie = "jan";
            p.nazwisko = "kowalski";

            oos.writeObject(p);
        }
    }
}

klasa Pakiet bez zmian, umieszczona w obydwu katalogach.

0

No przeciez widze ze masz klase Pakiet w roznych pakietach, czyli nie zrobiles tego co pisalem wczesniej. Wiadomo ze masz ClassCastException, przeciez ta sa rozne klasy. Wydaje mi sie ze juz wiecej nie pomoge, bo nie chcesz sobie pomoc. Pozdrawiam.

0

Chyba się nie rozumiemy. Przecież takie umieszczenie klas symuluje sytuację, gdy klient i serwer są na oddzielnych komputerach. A o to mi chodzi.
A ty masz pewnie na myśli umieszczenie klasy Pakiet w osobnej paczce... i wtedy klient i serwer mają do niej dostęp. Ale to nie jest to samo.
Co mi to da, skoro na osobnych komputerach znowu będę korzystał z różnych klas Pakietów i znowu będzie ClassCastException

0

Przeczytaj jeszcze raz caly watek.
Ponadto, widze ze klasa Pakiet jest na kliencie i serwerze w osobnych pakietach. Skad? Bo server i klient sa w osobnych, uzywasz klasy Pakiet, i nie masz nigdzie importu tej klasy. Wniosek jest 1 - albo klasa Pakiet jest w domyslnym pakiecie, albo jest w obu pakietach klient i sewer, obok tych klas. Pierwszy post sugeruje to drugie. Powiem wprost: masz zle!

0

Dobra, jutro z samego rana, gdy głowa będzie wyspana, przeczytam jeszcze raz twoje wskazówki,
najważniejsze, że jest sposób by ta serializacja i przesyłanie danych działało, prędzej czy później mam nadzieję dojdę do tego jak :)

0

tak w ogóle to dzięki za pomoc, twój pomysł z osobną paczką był oczywiście trafny. Nie wiem do końca co powodowało java.net.SocketException: Connection reset, ale pomógł flush() oraz close() po wysłaniu przez klienta pakietu.
Zastanawiam się tylko czy to powinienem umieścić w klauzuli finally?

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