Kłopot z ObjectInputStreamem w sockecie (Java)

Kłopot z ObjectInputStreamem w sockecie (Java)
D1
  • Rejestracja:ponad 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:7
0

Witam
piszę w celach szkoleniowych dość złożoną apkę w Javie 7 i utknąłem w miejscu, gdzie w ramach komunikacji klient-serwer (localhost) użytkownik jako jedną z opcji menu (wyświetlanego w pętli while i obsługiwanego mechanizmem switcha) prosi serwer o przesłanie listy zserializowanych osób, a klient je odbierze i wyświetli. Wyświetlanie robię w pętli - nie wpadłem na razie na prostszy pomysł. Próbowałem z 10 rozwiązań, ale: albo nie wyświetla niczego, albo wyświetla, co trzeba (czyli komunikacja jest ok) i przeskakuje do następnego case'a zamiast znowu pokazać menu. W innych caseach bez pętli nie problemu. Uproszczony kod jest taki (całość zajęłaby za dużo placu):

Kopiuj
 public class Serwer {

       ServerSocket providerSocket;
      //deklaracja referencji do strumieni

      void run() throws IOException, ClassNotFoundException {
    	 
    	  try {
          initialise(); //funkcja tworzy testowo dwa obiekty klasy Person, działa dobrze for sure
        //utworzenie ServerSocketa

          while (true) {
          //inicjalizacja strumieni, stworzenie zwykłego Socketa metodą accept(),odebranie opcji od klienta
         switch(opcjaOdKlienta)
                {
                case 1:                           
                	
                	System.out.println("Server should now send list of persons:");
                	 for (Person p : InnaKlasa.zbiórOfPersons.getPerson())  {      	
                		 oos.writeObject(p);    //oos to obiekt ObjectOutputStream
                	 }           
                	 break;
              case 2:
                     // nieistotne do końca
      

Klasa klient,w której jest problem, wygląda tak:

Kopiuj
public class Klient {

 Socket requestSocket;
 ObjectInputStream ois =null;

 void run() throws ClassNotFoundException,IOException {
        int choice = 0;

while (choice != 4) {
   //inicjalizacja strumieni
  //wyswietlenie menu i pobranie opcji od usera

 switch (choice)  {
              case 1: 
            	  dos.writeInt(1); //wysyła serwerowi polecenie przesłania obiektów Person
                  Person pp;
                  while(true)   {
    	        try{
                     System.out.println("Starting iteration");
            		 
    	             pp =(Person) ois.readObject();
            		  //if (pp==null) {ois.close(); System.out.println("Encountered pp==null..."); break; } 
            		  System.out.println(pp);          		 
    	 }	  
           	  catch (EOFException eof)  {
           		  ois.close();
           		  System.err.println("Entering  catch block");
           		  break ;         		  
           	  }
           
           	  }//koniec pętli while w casie
                  break;
             case 2:
                 ...

W takiej wersji program wyświetla dwie Person i wisi na "Starting iteration", próbowałem jakoś zamknąć strumień przez try-finally,ale nawet nie wchodził do bloku finally (a pisali, że zawsze sie wykona:P ). Wygląda na to, że strumień głupieje, kiedy wczytał wszystkie obiekty i nie mam pojęcia, co z tym zrobić (próbowałem pętlą for z tyloma iteracjami, ile ejst Persons, ale wtedy nie wyświetla niczego(?!) ). Warunek if(pp == null) też nic nie daje.
Byłby ktoś w stanie mnie poratować pseudokodem, w jaki sposób mogę obsłużyć wyświetlanie wszystkich obiektów i powrót do menu? Da się to w ogóle zrobić prościej niż zapisywać Persons do pliku i czytać stamtąd (o ile to by zadziałało?)

edytowany 2x, ostatnio: damian123b
Riddle
Sformatuj odpowiednio kod oraz wstaw go w znaczniki kolorujące składnie <code=java></code>. Inaczej nikt nie będzie chciał na to patrzeć.
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:około godziny
  • Lokalizacja:Koszalin
  • Postów:10094
0

Da się odczytać bez zapisywania do pliku. Pewnie też ktoś Ci tu pomoże jeżeli wstawisz kod w odpowiednie znaczniki <code class="java"></code> oraz wstawisz cały kod bez tych wyciętych fragmentów.

Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:około godziny
  • Lokalizacja:Koszalin
  • Postów:10094
0

Ehh, powinien wyglądać tak:

Kopiuj
public class Serwer {
 
    ServerSocket providerSocket;
 
    void run() throws IOException, ClassNotFoundException {
 
        try {
            initialise(); 
 
            while (true) {
                switch(opcjaOdKlienta) {
                    case 1:                           
                        System.out.println("Server should now send list of persons:");
                        for (Person p : InnaKlasa.zbiórOfPersons.getPerson())  {          
                            oos.writeObject(p);    //oos to obiekt ObjectOutputStream
                        }           
                        break;
                    case 2:
                         // nieistotne do końca

Kopiuj
public class Klient {
 
    Socket requestSocket;
    ObjectInputStream ois =null;
 
    void run() throws ClassNotFoundException,IOException {
        int choice = 0;
 
        while (choice != 4) {
 
            switch (choice)  {
                case 1: 
                    dos.writeInt(1); //wysyła serwerowi polecenie przesłania obiektów Person
                    Person pp;
                    while(true)   {
                    try {
                        System.out.println("Starting iteration");
 
                        pp =(Person) ois.readObject();
                        System.out.println(pp);                   
                    }      
                    catch (EOFException eof)  {
                        ois.close();
                        System.err.println("Entering  catch block");
                        break ;                   
                    }

                 }
                 break;
             case 2:
                 ...
        }
    }
}
D1
  • Rejestracja:ponad 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:7
0

dzięki, ale wolałbym żeby działał niż wyglądał...

Riddle
Nikt Ci nie odpowie jeżeli Twój kod będzie wyglądał jak śmietnik.
FP
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 7 lat
  • Postów:132
0

wydaje mi sie (ale nie jestem pewien) read object blokuje watek;

jest kilka rozwiazań;
jezeli chcesz wyswietlic obiekt (jezeli jest) to mozesz najpierw sprawdzic stan bufora odbioru np:
"available()
Returns the number of bytes that can be read without blocking."
https://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html

Ale to takie ... :/
Lepsze rozwianie: wyslij jeden obiekt a wewnatrz kolekcje przesylanych obiektow. (taki wrapper).
Albo: polecenie sygnaluzujace rozpoczecie przesylania danych (po odebraniu kazdego wrzucamy do jakiej kolekcji) a na koniec polecenie zakonczenia transmisji.
Po zakonczeniu wyswietlanie.

na pewno jeszcze jest kilka dobrych rozwiazan.

D1
  • Rejestracja:ponad 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:7
0

To by wiele tłumaczyło, że oczekujący strumień blokuje wątek. Sztuczki z while ((ois.available() ) próbowałem, nie działa.Wygląda, że ObjectInputStream ma buga i pozostaje liczyć, że w Javie 9 chłopaki coś poprawią. Za to jednokrotne przesłanie Seta zwracanego przez

Kopiuj
 InnaKlasa.zbiórOfPersons.getPerson() 

szybko i elegancko rozwiązało sprawę. Jednak najlepsze rozwiązania to te najprostsze:) Ale ja jestem idiota, że na to nie wpadłem.. Bardzo dziękuję za pomoc!!!

Jaca777
  • Rejestracja:ponad 9 lat
  • Ostatnio:11 miesięcy
0

Wygląda, że ObjectInputStream ma buga i pozostaje liczyć, że w Javie 9 chłopaki coś poprawią.

Zrzucanie winy na bibliotekę Javy powinno być bardzo, bardzo daleko w liście kroków przy naprawianiu błędów. Szczególnie przy używaniu tak często stosowanej klasy. Daj cały kod, z tego wycinka nic nie wywróżymy.

edytowany 6x, ostatnio: Jaca777
T1
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 8 lat
  • Postów:56
0

Wyczytałem na SO, że nie powinno się Socketem przesyłać obiektów innych niż typy proste (tak było dziwnie sformułowane). Osobiście nie miałem problemów z przesyłaniem własnych obiektów, w których polami były typy proste, String i Enum. Natomiast nie mogłem przesłać tablic obiektów. Najlepiej użyć JSON-a lub czegoś podobnego.

Riddle
Możesz wysyłać obiekty inne niż typy proste. W zasadzie możesz wysłać wszystko co da się zserializować.
T1
Moje obiekty były serializowane tak jak i ich pola, jednak odczytanie pól obiektu przez klienta zwracało nulle więc sam nie wiem.
Riddle
Musiałeś zrobić coś źle. Milion razy używałem tego mechanizmu i zawsze dostawałem to co wysyłałem.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.