Aplikacja klient - serwer (problem z wątkami)

0

Hej,
Piszę aplikację klient - serwer (serwer obsługuje kilku klientów). Jeśli klient wysyła komunikat do serwera, to serwer przekazuje ten komunikat do wszystkich pozostałych klientów, z wyjątkiem klienta, który nadał komunikat. Jeśli klient wyśle komunikat do serwera, to otrzyma od niego potwierdzenie ACK. Poza tym jeśli serwer prześle komunikat do pozostałych klientów, to otrzyma również komunikat ACK od każdego z tych klientów z osobna. Niestety mam problem z tą drugą częścią, nie potrafię odebrać komunikatu "ACK" od pozostałych klientów... Jest jakiś błąd w metodzie run() w Connection.java (zaznaczyłam komentarzem gdzie) i nie mam pojęcia dlaczego to nie działa:/ Bardzo proszę o pomoc. Dzięki z góry

Serwer.java

public class Serwer extends Thread {
    Socket klient;
    ServerSocket serwer;
    Connection c;

    Vector<PrintWriter> allOutput = new Vector<PrintWriter>();
    Vector<BufferedReader> allInput = new Vector<BufferedReader>();
    Vector<Connection> allConnections = new Vector<Connection>();

    public Serwer(ServerSocket ss) throws IOException
    {
        serwer=ss;
    }
    
    @Override
    public void run()
    {
        while(true)
        {
            try
            {
                    klient=serwer.accept();
                    System.out.println("Klient podłączył się do serwera");
                    Connection con=new Connection(klient,this);
                    allConnections.add(con);
                    Thread t=new Thread(con);
                    t.start();                
            }
            catch(IOException e) {}
            
        }
    }

}

Connection.java

public class Connection implements Runnable{

    PrintWriter out1;
    BufferedReader in1;
    Socket klient1;
    Serwer serwer;

    TimerTimeout timer;

    int whichClient;

    public Connection(Socket klient1, Serwer serwer) throws IOException
    {
        this.klient1=klient1;
        out1=new PrintWriter(klient1.getOutputStream(), true);
        in1=new BufferedReader(new InputStreamReader(klient1.getInputStream()));
        this.serwer = serwer;

        serwer.allInput.add(in1);
        serwer.allOutput.add(out1);

        whichClient = serwer.allInput.size() - 1;
        System.out.println("KlientNr: "+ whichClient);

        timer = new TimerTimeout();
    }
    
    public void closeConnection()
    {
        try
        {
            if (in1 != null) in1.close();
            if (out1 != null) out1.close();
            if (klient1 != null) klient1.close();
            serwer.allOutput.remove(whichClient);
            serwer.allInput.remove(whichClient);
            serwer.allConnections.remove(whichClient);

            for(int i = whichClient ; i< serwer.allConnections.size() ; i++)
            {
                serwer.allConnections.get(i).whichClient--;
            }
        }
        catch(IOException e) {}
    }

    //@Override
    public void run()
    {
        String s;
        try
        {
            while(!(s=in1.readLine()).equals("bye"))
            {

                System.out.println("Przeczytałem: "+s+" od klienta "+whichClient);
                //Odsyłam do klienta potwierdzenie "ACK" otrzymania komunikatu
                out1.println("ACK");
                System.out.println("Wysłałem ACK do klienta"+ whichClient);

                int liczbaKlientow = serwer.allInput.size();

                //Wysyłam do pozostałych klientów komunikat i czekam na odpowiedzi ACK
                for(int i = 0; i < liczbaKlientow ; i++)
                {
                    if(i != whichClient) {
                        serwer.allOutput.get(i).println(s);
                        //**** TU JEST PROBLEM PROGRAM OMIJA PONIŻSZE LINIJKI ****
                        String ack = serwer.allInput.get(i).readLine();
                        System.out.println("przeczytałem"+ack);
                    }               
                }
                
                Thread.sleep(100);
            }

            System.out.println("Klient "+whichClient+" rozłącza się z serwerem");
            out1.println("bye");
            closeConnection();
        }
        catch(SocketException ex)
        {
            System.out.println("Klient "+whichClient+" niespodziewanie rozłączył się z serwerem");
            closeConnection();
        }
        catch (InterruptedException ex)
        {
            Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, null, ex);
        }            
        catch (IOException ex)
        {
            Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
}

ClientInterface.java

//Metoda do przycisku odpowiedzialna za wysłanie komunikatu
 private void sendButtonActionPerformed(java.awt.event.ActionEvent evt) {                                           

        if(klient.isConnected = true)
        {
                //Wysyłam komunikat do serwera
                klient.out.println(jTextArea1.getText());
                while ( klient.getACK == false) {}
                klient.getACK = false;
                
        }

    }    

Client.java

public class Client extends Thread
{
    PrintWriter out = null;
    BufferedReader in = null;
    Socket klient = null;

    ClientInterface interf = null;
    boolean isConnected = false;

    String server;
    int port;

    public boolean getACK = false;

    public Client(String server,int port)
    {
        this.server = server;
        this.port = port;
    }

    public void addInterface(ClientInterface interfejs)
    {
         this.interf=interfejs;
    }

    public void closeConnection()
    {
            isConnected = false;
            out.println("bye");
    }

    public void connect()
    {
        try
        {
            klient=new Socket(server,port);
            out=new PrintWriter(klient.getOutputStream(), true);
            in=new BufferedReader(new InputStreamReader(klient.getInputStream()));

            isConnected = true;
            start();
        }
        catch(UnknownHostException e)
        {
            System.err.println("Don't know about host: "+server);
        }
        catch(IOException e)
        {
            System.err.println("Couldn't get I/O for the connection to: "+ server);
        }
    }
    
    @Override
     public void run()
     {
        String odp;
        try
        {
            while( isConnected && !(odp = in.readLine()).equals("bye"))
            {
                if(odp.equals("ACK"))
                {
                    getACK = true;
                    System.out.println("Otrzymałem ACK");
                    odp = "";
                }
                else
                {
                    interf.jTextArea2.append(odp+"\n");
                    odp = "";
                    out.println("ACK");
                    Thread.sleep(200);
                }
 
            }
                System.out.println("Rozłączam...");
                in.close();
                out.close();
                klient.close();
        }
        catch (InterruptedException ex)
        {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (IOException ex)
        {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
0

Udało mi się wydedukować, że to jest problem z wątkami... gdy wątek "Connection1" (odpowiedzialny za połączenie z klientem 1) wysyła komunikaty do pozostałych wątków obsługujących pozostałych klientów (Connection2, Connection3...) to ta linijka:

String ack = serwer.allInput.get(i).readLine()

już nie działa, bo inne wątki (Connection2, Connection3...) mają już coś na strumieniu wejściowym i zaczynają swoją pętlę:

 while(!(s=in1.readLine()).equals("bye") )
....

Zatem muszę jakoś powstrzymać pozostałe "Connections" od pobierania danych ze strumienia... Dodanie "synchronized" do run-a niewiele dało... Ma ktoś jakieś pomysły?

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