Kolejny komunikator

0

Witam. Przeszukałem forum i nadal nie mogę rozwiązać swojego (nie znalazłem odpowiedzi) problemu. Otóż mam komunikator (klient i serwer). Do serwera łączy się nieograniczona liczba użytkowników i to co dany z nich napisze, automatycznie trafia (poprzez serwer) do każdego podłączonego w danej chwili klienta (metoda broadcast_message(String message)). Stworzyłem HashMap, która przechowuje identyfikator (w tym wypadku na razie nick) oraz klasę odpowiedzialną za komunikację (ServerReadingStreamClass). Czytałem również, że trzeba podzielić wiadomość od klienta splitem, na formę od_kogo do_kogo wiadomość. Co też uczyniłem. Jednak nie wiem nadal jak przesłać coś od jednego klienta do drugiego [???] . Pozdrawiam

class ServerReadingStreamsThreadClass implements Runnable{
	
		private Socket nowe_gniazdo;
		private DataInputStream dane_wej;
		private DataOutputStream dane_wyj;
		private JTextArea okno_danych;
		public static ArrayList<DataOutputStream> clients_out_streams = new ArrayList<DataOutputStream>();
		private HashMap<String, ServerReadingStreamsThreadClass> mapa = new HashMap<String, ServerReadingStreamsThreadClass>();
			
		ServerReadingStreamsThreadClass(Socket nowe_gniazdo, JTextArea okno_danych){
			this.nowe_gniazdo = nowe_gniazdo;
			this.okno_danych = okno_danych;
			}
		
		public void broadcast_message(String message){
			Iterator<DataOutputStream> ilu_klientow = clients_out_streams.iterator();
			while(ilu_klientow.hasNext()){
				try{
					DataOutputStream dos = ilu_klientow.next();
					dos.writeUTF(message);
					dos.flush();
				}catch (IOException e) {
					e.getMessage();
				}
			}
		}
		
		public String msg_from(String message){
			String from = null;
			String []array = message.split(" ");
			from = array[0];
			return from;
		}
		
		public void run() {
			String message;
			try{
				dane_wej = new DataInputStream(nowe_gniazdo.getInputStream());
				dane_wyj = new DataOutputStream(nowe_gniazdo.getOutputStream());
				clients_out_streams.add(dane_wyj);
			}catch (IOException e) {
				e.getMessage();
			}
			while(true){
				try{
				while((message = dane_wej.readUTF())!=null){
				okno_danych.append("\n"+message);
				mapa.put(msg_from(message), this);
				broadcast_message(message);
				}
				}catch (IOException e) {
					e.getMessage();
				}
			}
		}	
	}

A to jest klasa ServerCommunicationClass:

class ServerCommunicationClass {

	private static ServerSocket server_socket;
	private static DataOutputStream out_data;

	public static void nowy_server_service(int port,JTextArea receive_field){
		
		try{
			server_socket = new ServerSocket(port);
			receive_field.append("Serwer jest uruchomiony...");
		}catch (IOException e) {
			e.getMessage();
		}
		while(true){
			ServerReadingStreamsThreadClass serv_thr_class;
			try{
				serv_thr_class = new ServerReadingStreamsThreadClass(server_socket.accept(),receive_field);
				Thread server_thread = new Thread(serv_thr_class);
				server_thread.start();
			}catch (IOException e) {
				e.getMessage();
			}
		}
	}
}
0

Przecież broadcast_message po kolei wysyła do strumienia wyjściowego każdego klienta. Wystarczy więc wyizolować taki strumień dla klienta o którego konkretnie chodzi i po sprawie.

I tak w ogóle, to zmienna ilu_klientów jest źle nazwana. Powinna nazywać się strumienie_klientów lub coś podobnego. W obecnej nazwie myli i może dlatego nie możesz tego przeskoczyć. Powinieneś napisać metodę przesyłającą komunikat na jeden konkretny strumień (jako argument) i to ją wywoływać w broadcast_message().

Poza tym co właściwie robi ta obsługa wyjątku w broadcast_message? Bo jak dla mnie to nic - pobiera komunikat w kosmos i olewa go. Poza tym należałoby również wywalić deklarację zmiennej dos poza pętlę bo wewnątrz niej robi to tylko niepotrzebne ruchy na stosie, szczególnie w połączeniu z try. Ale to już kosmetyka.

Kiedy będziesz już mieć metodę na przesłanie pojedynczego komunikatu do konkretnego klienta, to potrzebujesz już tylko metody, która pozwoli wybrać klienta i odda jego strumień, który dasz do metody przesyłającej komunikat do jednego klienta.

0

Na początku podziękuję za wskazówki odnośnie samego kodu. Co do metody broadcast to zajmowała się opisywanymi przez Ciebie działaniami. Teraz odnośnie problemu...stworzyłem tak jak mówiłeś sobie prostą metodę (w klasie ServerReadingStreamsClass), która ma za zadanie wysyłać wiadomość do odpowiedniego klienta. I wydaje mi się, że to właśnie tak ma wyglądać, jednak działa ona tylko, jeśli w mapie znajduje się szukany użytkownik (co jest sensowne). I tu jest teraz problem, bo w mapie, bez względu na to ilu się klientów podłączy, to zawsze istnieje tylko ostatni wpis (tak jakby nadpisywana była). Pewnie, źle umieszczam elementy w Mapie, jednak nie wiem dlaczego (bo Mapa zawiera nick usera oraz klasę ServerReadingStreamsThreadClass) [???] . Pozdrawiam
To jest nowa metoda (o coś takiego chodziło) ???:

public void send_message_2_client(String message){
		if(!(msg_to(message)==null)){
			if(msg_to(message).equalsIgnoreCase("miki")){
				try{
				mapa.get("miki").dane_wyj.writeUTF(msg(message));
                                }catch (IOException e) {
				System.err.print("Nie ma MIKIEGO\n");
				}
				}else{
				broadcast_message(message);
				}
				}
			}

Natomiast umieszczanie elementów w HashMapie, jest w kodzie we wcześniejszym poście (w metodzie run()).
Pozdrawiam

0

Utwórz metodę, która robi to samo co broadcast_message(), ale niech posiada ona dwa argumenty String Message oraz DataOutputStream dos. Po prostu wytnij jeden przebieg while z broadcast_message dla konkretnego strumienia.

Zauważ, że kod, który podałeś dodaje jeden strumień do clients_out_streams bez względu na to ilu klientów wyśle wiadomość. A na podstawie tego jednego strumienia określasz liczbę klientów, która w takim wypadku musi być równa 1 dla pojedynczego obiektu ServerReadingStreamsThreadClass.
Nie jest ważne ile komunikatów przyjdzie i ilu klientów je wyśle. Tak czy inaczej otrzymujesz liczbę klientów równą 1. No chyba, że jeden obiekt ServerReadingStreamsThreadClass będzie miał kilka razy uruchomioną metodę run, ale wydaje mi się, że pojedynczy obiekt będzie wykorzystany jednokrotnie.

0

Proszę o jeszcze trochę wyrozumiałości :). Mógłbyś jeszcze bardziej rozwinąć:

Po prostu wytnij jeden przebieg while z broadcast_message dla konkretnego strumienia

Gdyż nie wiem jak to zrobić :(

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