Prosty czat.

0

Witam.

Poniżej przedstawiam kod klienta i serwera prostego czatu.

Serwer:



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

public class CzatSerwer{
   ArrayList<ObjectOutputStream> strumienieWyjsciowe;
   ObjectInputStream wej;
   
   public class ObslugaKlientow implements Runnable{
      BufferedReader czytelnik;
      Socket gniazdo;
      
      public ObslugaKlientow(Socket clientSocket){
         try{
            gniazdo = clientSocket;
            wej = new ObjectInputStream(gniazdo.getInputStream());
         }
         catch(Exception ex){
            ex.printStackTrace();
         }
      }
      
      public void run(){
         String wiadom;
         Object o1 = null;
         Object o2 = null;
         try{
            while((o1 = wej.readObject()) != null){   
               o2 = wej.readObject();
               System.out.print("Odczytano obiekty");
               rozesliDoWszystkich(o1,o2);
            }
         }
         catch(Exception ex){
            ex.printStackTrace();
         }
      }
   }
   
   public static void main(String[] args){
      new CzatSerwer().doRoboty();
   }
   
   public void doRoboty(){
      strumienieWyjsciowe = new ArrayList<ObjectOutputStream>();
      try{
         ServerSocket serverSock = new ServerSocket(5000);
         while(true){
            Socket gniazdoKlienta = serverSock.accept();
            ObjectOutputStream wyj = new ObjectOutputStream(gniazdoKlienta.getOutputStream());
            strumienieWyjsciowe.add(wyj);
            
            Thread t = new Thread(new ObslugaKlientow(gniazdoKlienta));
            t.start();
            
            System.out.println("Mamy połączenie");
         }
      }
      catch(Exception ex){
         ex.printStackTrace();
      }
   }
   
   public void rozesliDoWszystkich(Object o1, Object o2){
      Iterator it = strumienieWyjsciowe.iterator();
      while(it.hasNext()){
         try{
            ObjectOutputStream wyj = (ObjectOutputStream) it.next();
            wyj.writeObject(o1);
            wyj.writeObject(o2);
            System.out.println("Wysłano obiekty");
         }
         catch(Exception ex){
            ex.printStackTrace();
         }
      }
   }
}

Klient:


import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class CzatKlient{
   JTextArea odebraneWiadomosci;
   JTextField wiadomosc;
   BufferedReader czytelnik;
   PrintWriter pisarz;
   Socket gniazdo;
   
   ObjectInputStream wej;
    ObjectOutputStream wyj;
   
   String NICK;
   
   public static void main(String[] args){
      CzatKlient klient = new CzatKlient();
      klient.doDziela(args[0]);
   }
   
   public void doDziela(String nick){
      NICK = nick;
      JFrame ramka = new JFrame("Klient pogawedek");
      JPanel panelGlowny = new JPanel();
      
      odebraneWiadomosci = new JTextArea(15,50);
      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 przyciskWysli = new JButton("Wyśli");
      przyciskWysli.addActionListener(new PrzyciskWysliListiner());
      
      panelGlowny.add(przewijanie);
      panelGlowny.add(wiadomosc);
      panelGlowny.add(przyciskWysli);
      
      konfigurujKomunikacje();
      
      Thread watekOdbiorcy = new Thread(new OdbiorcaKomunikatow());
      watekOdbiorcy.start();
      
      ramka.getContentPane().add(BorderLayout.CENTER, panelGlowny);
      ramka.setSize(600,500);
      ramka.setVisible(true);
   }
   
   private void konfigurujKomunikacje(){
      try{
         gniazdo = new Socket("127.0.0.1", 5000);

         wyj = new ObjectOutputStream(gniazdo.getOutputStream());
         wej = new ObjectInputStream(gniazdo.getInputStream());
         System.out.println("Obsługa sieci przygotowana");
      }
      catch(IOException ex){
         ex.printStackTrace();
      }
   }
   
   public class PrzyciskWysliListiner implements ActionListener{
      public void actionPerformed(ActionEvent ev){
         try{
            wyj.writeObject(wiadomosc.getText());
            wyj.writeObject(NICK);
         }
         catch(Exception ex){
            ex.printStackTrace();
         }
         wiadomosc.setText("");
         wiadomosc.requestFocus();
      }
   }
   
   public class OdbiorcaKomunikatow implements Runnable{
      public void run(){
         String wiado;
         Object o1 = null;
   
         try{
            while((o1 = wej.readObject()) != null){
               String wiadom = (String) o1;
               String nick = (String) wej.readObject();
               odebraneWiadomosci.append(nick +" "+ wiadom + "\n");
            }
         }
         catch(Exception ex){
            ex.printStackTrace();
         }
      }
   }
}

Testując czat na własnym komputerze napotkałem problem. Pracuje w wierszu poleceń i oczywiście serwer i klienta odpalam w odzielnycj okanch cmd.

Gdy otwieram jednego klienta, wszystko działa dobrze, serwer otrzymuje wiadomość i wysyła.

Gdy uruchamiam dwóch klientów jest kłopot. Gdy wysyłam wiadomość z klienta odpalonego jako drugi, wszystko działa, serwer rozsyła wiadomośći do wszystkich. Jednak gdy próbuje wysłać wiadomość z klienta odpalonego jako pierwszy nic się nie dzieje, serwer nie otrzymuje obiektów.
Gdy po tej próbie wracam do drugiego klienta i próbuje wysłać coś dostaje na serwerze dwa wyjątki "StreamCorruptException"

java.io.StreamCorruptedException: invalid type code: 00
        at java.io.ObjectInputStream.readObject0(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at CzatSerwer$ObslugaKlientow.run(CzatSerwer.java:37)
        at java.lang.Thread.run(Unknown Source)
java.io.StreamCorruptedException: invalid type code: 00
        at java.io.ObjectInputStream.readObject0(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at CzatSerwer$ObslugaKlientow.run(CzatSerwer.java:32)
        at java.lang.Thread.run(Unknown Source)

O co może chodzić ?

Pozdrawiam :)

0

Kod jest tragiczny, to raz.
Dwa, nie ma tu ŻADNEJ synchronizacji, a powinna. Co się stanie jak w trakcie rozsyłania wiadomości przez serwer dołączy się nowy user i kolekcja z klientami się zmieni? Powinieneś tu mieć znacznie więcej klas, które będą enkapsulować część funkjconalności, bo mieszasz strasznie poziomy abstrakcji
Trzy, twój problem polega zapewne na tym że próbujesz utworzyć klientów na tym samym porcie ;]

0

Kod oczywiście do poprawy (ten jest żywcem wzięty z książki). Nie bardzo rozumiem sprawy z tymi portami. Wszyscy klienci są odpalania z tego samego komputera i są na tym samy porcie?
Tak to rozumiem ;p Czyli nie można testować takiej komunikacji na jednym komputerze?

Pozdrawiam.

//coś mi się wydaje, że źle to rozumiem...

0

Mozna, ale każdy klient musi mieć swój port, bo inaczej to nie zadziała. Porty w systemie to jest sposób na identyfikacje programów które łączą się z siecią. Na danym porcie może siedzieć tylko jeden program ;]

edit: ale ok, ty uruchamiasz tylko 1 serwer więc powinno być ok. Wprowadź do kodu synchronizację a potem się zastanowimy co się dzieje. Ja obstawiam że może to być właśnie problem z jakimś jednoczesnym dostępem.

0

Jest jeszcze coś o czym nie napisałem wcześniej. Próbuje tu wysłać 2 obiekty o1 i o2. Gdy wprowadze poprawkę, że klient wysyła tylko jeeden obiekt, serwer go odbiera i rozsyła dalej wszystko działa poprawnie.

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