Serwer komunikujący się z wieloma klientami

0

Wiem, że temat przewijał jednak nie mogę znaleźć rozwiązania mojego problemu. Napisałem serwer, który w teorii powinien połączyć wiele klientów, klient wysyła wiadomość do serwera, a ten ją rozsyła do wszystkich klientów włącznie z wysyłającym. Poniżej zamieszczam kod:

import java.net.ServerSocket;
import java.net.Socket;

public class ServerChat {
    public static void main(String[] args) {
        try {
            ServerEngine server = new ServerEngine(8189, 20);

            while(true) {
                Socket s = server.getServerSocket().accept();
                server.addConnection(s);
            }
        } catch(Exception ex) {
            System.err.println(ex);
        }
    }

}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class ServerEngine {
    private ServerSocket serverSocket;
    private Socket[] sTab;
    private volatile int connections;

    public ServerEngine(int port, int maxConnections) throws IOException {
        serverSocket = new ServerSocket(port, maxConnections);
        sTab = new Socket[maxConnections];
    }

    public ServerSocket getServerSocket() {
        return serverSocket;
    }

    public void addConnection(Socket s) throws IOException { 
        synchronized(sTab) { 
            for(int i = 0; i < sTab.length && sTab != null; i++) {
                if(i < sTab.length) {
                    connections++;
                    System.out.println("Connections: " + connections);
                    sTab[i] = s;
                    Runnable r = new Broadcast(i);
                    Thread t = new Thread(r);
                    t.start();
                } else {
                    s.close();  
                }
            }
        }
    }

    public class Broadcast implements Runnable {
        public int index;

        public Broadcast(int i) {
            index = i;
        }

        public void run() {
            try {
                synchronized(sTab) {
                    if(sTab[index] != null) {
                        InputStream inStream = sTab[index].getInputStream();
                        OutputStream outStream = sTab[index].getOutputStream();

                        Scanner in = new Scanner(inStream);
                        PrintWriter out = new PrintWriter(outStream, true);

                        if(in.hasNextLine()) {
                            String incoming = in.nextLine();
                            //Close connection if incoming == "disconnect"
                            if(incoming.equals("disconnect")) {
                                sTab[index].close();
                                sTab[index] = null;
                                connections--;
                            } else {
                                out.println(incoming);
                            }
                        }
                    }
                }
            } catch(IOException ex) {
                System.err.println(ex);
            }
        }
    }
}

Serwer nie wchodzi w metodzie addConnection(Socket s) {...} przy warunku w pętli sTab != null, jeżeli go usunę serwer wchodzi w pętlę jednak zapełnia tablicę sTab do końca jednym połączeniem.

1

Po pierwsze: i < sTab.length && sTab != nullDałeś warunki w złej kolejności, jeśli sTab będzie null to i tak Ci tutaj wywali NullPointerException (przy sTab.length) .. w ogóle warunek sTab !=null powinien być poza pętlą..
Po drugie: mamy XXI wiek, zamiast bawić się z tablicami, użyj jakiejś listy.
Po trzecie: wywal w ogóle tę pętlę, przecież to jest bez sensu, nie widzisz tego?

0

Zmieniłem metodę addConnection jednak przy próbie połączenia dostaję komunikat

telnet localhost 8189
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.

zmieniona metoda:

public void addConnection(Socket s) throws IOException { 
        synchronized(sTab) { 
            for(int i = 0; i < sTab.length; i++) {
                if(sTab[i] != null) {
                    connections++;
                    System.out.println("Connections: " + connections);
                    sTab[i] = s;
                    Runnable r = new Broadcast(i);
                    Thread t = new Thread(r);
                    t.start();
                } else {
                    s.close();  
                }
            }
        }

Pętla jest po to żeby wiadomość od jednego klienta trafiła do całej reszty

0

Skoro tak, to robisz to kompletnie źle... Przeanalizuj swój kod i pomyśl...

edit: jak nie dasz rady, to mogę Ci dać odpowiedź... ale lepiej Ci zrobi, jeśli sam dojdziesz co jest źle. Generalnie myśl najpierw, pisz później.

0

Zmieniłem kod jednak aplikacja nadal nie zachowuje się tak jak powinna.
Po usunięciu pętli serwer wykonuje wątek tylko raz, a chodzi o to żeby wykonywał wszystkie wątki.
Zasada działania kilku klientów łączy się do jednego serwera -> serwer odbiera od klienta[n] wiadomość, odsyła ją do niego oraz rozsyła ją do reszty podłączonych klientów.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

public class ServerEngine {
    private ServerSocket serverSocket;
    private ArrayList<Socket> sTab;
    private volatile int connections;

    public ServerEngine(int port, int maxConnections) throws IOException {
        serverSocket = new ServerSocket(port, maxConnections);
        Socket socket = new Socket();
        sTab = new ArrayList<Socket>();
        connections = 0;
    }

    public ServerSocket getServerSocket() {
        return serverSocket;
    }

    public void addConnection(Socket s) throws IOException { 
        synchronized(sTab) {
            sTab.add(connections, s);
            System.out.println("Connections: " + connections);

            Runnable r = new Broadcast(connections);
            Thread t = new Thread(r);
            t.start();

            connections++;
        }
    }

    public class Broadcast implements Runnable {
        public int index;

        public Broadcast(int i) {
            index = i;
        }

        public void run() {
            try {
                synchronized(sTab) { 
                    Socket s = sTab.get(index);
                    InputStream inStream = s.getInputStream();
                    OutputStream outStream = s.getOutputStream();

                    Scanner in = new Scanner(inStream);
                    PrintWriter out = new PrintWriter(outStream, true);

                    if(in.hasNextLine()) {
                        String incoming = in.nextLine();
                        //Close connection if incoming == "disconnect"
                        if(incoming.equals("disconnect")) {
                            s.close();
                            sTab.remove(index);
                            connections--;
                        } else {
                            out.println(incoming);                      
                        }   
                    }
                }
            } catch(IOException ex) {
                System.err.println(ex);
            }
        }
    }
}

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