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