Aplikacja Klien-Serwer - identyfikacja użytkowników

0

Witam wszystkich bardzo serdecznie.

Mam taki "drobny" problem. Mianowicie jako projekt mam do napisania komunikator internetowy na dowolnie wybranym protokole. W pierwszej wersji będzie on działał na TCP w kolejnych rozwojowych TCP zastąpię SSL. Ale protokół to najmniejsze moje zmartwienie. Otóż pytałem wujka google, przekopałem serwis 4programmers.net i jakoś nie mogę znaleźć sensownej odpowiedzi na pytanie:
"Jak napisać wielowątkowy serwer który identyfikowałby użytkowników oraz wysyłał wiadomość od użytkownika A tylko do użytkownika B?"

W sieci jest całe mnóstwo przykładów aplikacji klient-serwer, łącznie z wielowątkowymi serwerami ale wszystkie opisane serwery działają na zasadzie broadcastu/chatu - rozsyłają wiadomość do wszystkich klientów.

Świta mi tylko tyle, że:

  • serwer powinien być wielowątkowy
  • odpowiednie wątki powinny wymieniać między sobą komunikaty od/do klientów
  • do przechowywania bazy userów można wykorzystać bazę danych MySQL/PostgreSQL

Stąd moja prośba do starych wyjadaczy i osób bardziej zaawansowanych w kodowaniu w Javie. Jak się zabrać za wymianę informacji między wątkami. Baza danych może poczekać nie jest w tej chwili niezbędna. Przygodę z kodowaniem w Javie dopiero zaczynam stąd moje dziwne i być może dziecinne pytania.

Mam nadzieję, że dość jasno sprecyzowałem założenia serwera ;) Interfejs tekstowy. Ewentualne GUI w kolejnym semestrze jako "nakładka" na tekstową wersję.

Z góry dziękuję za odpowiedzi i podpowiedzi.

P.S Dodam jeszcze, że na forum znalazłem odnośnik do interesującej mnie wersji serwera ale link jest już nieczynny (Error 404)) a w dziale download jeden z linków (właśnie ten odnośnie serwera wielowątkowego) również jest nieczynny.

Vidharr says hail!

P.S.2
Po kolejnych godzinach walki, szperaniu po googlach, etc z pomocą takich i owakich HowTo, tutoriali i książek otrzymałem taki oto kod serwera:

import java.io.*; /* import bibliotek WE/Wy */
import java.net.*; /*import bibliotek odpowiedzialnych za komunikacje sieciowa */
import java.util.*; /* import bibliotek narzedziowych */

/*
  Klasa serwer odpowiedzialna za komunikacje pomiedzy uzytkownikami
  Dla każdego podlaczonego uzytkownika tworzony jest nowy watek
*/
public class Server //glowna klasa serwera
{
  ArrayList<PrintWriter> C_OutStreams;


  public class CH implements Runnable //CH (Client Handler) wewnetrzna klasa tworzaca uchwyty do poszczegolnych klientow
  {
    BufferedReader C_BR; //strumien buforowanych danych przychodzacych od klienta
    Socket C_socket; //gniazdo polazceniowe odbierajace dane od klienta

    public CH (Socket ClientSocket) //konstruktor klasy
    {
      try //probuj utworzyc polaczenie na podanym gniezdzie, utworz buforowane strumienie I/O
	{
	  C_socket = ClientSocket; //otworz gniazdo nr ClientSocket
	  InputStreamReader Input = new InputStreamReader(C_socket.getInputStream()); 
		//utworz strumien wejscia i pobieraj do niego dane przesylane z gniazda klienta
	  C_BR = new BufferedReader (Input);
		//buforuj przychodzace dane
	}//koniec bloku try
      catch (Exception E) //przechwyc ewentualne wyjatki oraz poinformuj o tym
 	{
	  System.out.println("Cos poszlo nie tak!"); //poinformuj o wystapieniu bledu
	  E.printStackTrace(); //powiedz gdzie wystapil blad 
	  System.out.println("Blad: " + E.getMessage()); //podaj szczegoly dotyczace bledu
	}//koniec bloku przechwytywania i obslugi wyjatkow
    }//koniec konstruktora

   public void run() //wlasna implementacja metody Run(), "ozywianie" watku
    {
      String msg; // wiadomosc przychodzaca i rozsylana dalej

      try //probuj odbierac i rozsylac wiadomosci
	{
	  while ((msg = C_BR.readLine()) != null)
		//tak dlugo jak bufor wejsciowy NIE jest pusty
	   {
	     System.out.println("otrzymano: " + msg); //na konsoli serwera wysietl ta wiadomosc
	     Broadcast(msg); //rozeslij wiadomosc do wszystkich uzytkownikow lacznie z nadwaca
			//Broadcast(String message) - wlasna metoda do rozsylania wiadomosci
	   }//koniec petli while 
	}//koniec bloku try
      catch(Exception E) //przechwyc ewentualne wyjatki i poinformuj co to za blad
	{
	  System.out.println("Cos poszlo nie tak!");
	  E.printStackTrace();
	  System.out.println("Blad: " + E.getMessage());
	}//koniec bloku przechwytywania i obslugi wyjatkow
    }//koniec metody run()
  }//koniec klasy wewnetrznej CH


 public static void main (String[] args) //glowna metoda klasy Server
  {
    new Server().Uruchom(); //stworz i uruchom Server
  } //koniec metody main()

 public void Uruchom() //metoda obslugujaca zycie watku
  {
    C_OutStreams = new ArrayList<PrintWriter>(); //tablica przechowujaca strumienie wyjscia do klientow, kazdy nowy
				//strumien to nowe polaczenie, watek i klient
    try //proba utworzenia gniazda serwera, tworzenia watkow potomnych
     {
       ServerSocket S_socket = new ServerSocket(4096); //utworz gniazdo dla serwera na porcie 4096
		//port nalezy wybrac z zakresu 1024-65536 poniewaz na ogol te porty sa wolne
		//porty z zakresu 0-1023 sa zarezerwowane dla standardowych aplikacji
		//klient-serwer, takich jak serwery www, ftp, ssh, telnet, pop, imap czy smtp
       while(true) //petla nieskoniczona, wykonywana przez cale "zycie" watku
	{
	  Socket ClientSocket = S_socket.accept(); //nasluchuj i akceptuj polaczenia przychodzace
						//przychodzace na port serwera
	  PrintWriter Output = new PrintWriter (ClientSocket.getOutputStream());
		//utworz strumien wyjsciowy na gniezdzie klienta
	  C_OutStreams.add(Output); //do tablicy klientow dodaj nowy strumien wyjsciowy od 
					//nowego klienta
	  Thread Th = new Thread (new CH (ClientSocket)); //utworz nowy watek dla klienta
	  Th.start(); //uruchom watek
	  System.out.println("Pomyslnie nawiazano polaczenie z serwerem. Mozna rozpoczac komunikacje");
	}//koniec petli while
     }//koniec bloku try
     catch (Exception E) //obsluga ewentualnych wyjatkow
      {
	System.out.println("Cos poszlo nie tak!");
	E.printStackTrace();
	System.out.println("Blad: " + E.getMessage());
      }//koniec obslugi wyjatkow
  }//koniec metody Uruchom()

 public void Broadcast(String message) //metoda rozgloszeniowa odpowiedzialna za
					//rozsylanie wiadomosci do wszystkich uzytkownikow
  {
    Iterator C_Ile = C_OutStreams.iterator(); //sprawdz ilu jest podlaczonych klientow
							//i zapamietaj to w zmiennej pomocniczej
    while(C_Ile.hasNext())//dopoki nie trafisz na ostatniego klienta probuj
     {
	try
	 {
	   PrintWriter Output = (PrintWriter) C_Ile.next();
	   Output.println(message); //wyswietl wiadomosc u klienta
	   Output.flush();//wyczysc bufory
	 }//koniec bloku try
	catch (Exception E)
	 {
	   System.out.println("Cos poszlo nie tak!");
	   E.printStackTrace();
	   System.out.println("Blad: " + E.getMessage());
	 }//koniec obslugi wyjatkow
     }//koniec while 
  }//koniec metody Broadcast

}//koniec klasy glownej

Ok kod poprawiony, rzutowania nie ma (trochę jeszcze pogrzebałem i znalazłem co jest nie halo) teraz pozostałe "problemy" Dzięki za naprowadzenie. Odnośnie identyfikacji userów podczas podłączania to zaraz coś pokombinuję i postaram się odpowiednio zmodyfikować kod. Uwzględniam opcję działania a'la IRC czyli globalne wiadomości a po odpowiednim słowie kluczowym (typu /msg nick wiadomość) tylko u zadanego użytkownika pokazuje się komunikat. Trochę to toporne i ograniczone ale w pierwszych wersjach może działać i tak ;) Potem będę modyfikował dalej :)

0

Generalnie każdy użytkownik komunikatora ma swój unikalny identyfikator UID. W momencie nawiązania połączenia serwer powinien zarządać jakiejś formy autoryzacji. Po poprawnej autoryzacji, dodaj socket klienta do jakiegoś HashMap'a z kluczem (UID). Teraz jeżeli użytkownik A będzie chciał przesłać wiadomość do użytkownika B, wówczas dostęp do jego socket'u będziesz miał na podstawie jego UID np.:

Socket user = userSocketMap.get('B');

Co do serwera wielowątkowego zajrzyj na:
http://java.sun.com/developer/onlineTraining/Programming/BasicJava2/socket.html#multi

0

A fuj... generalnie problemy z rzutowaniem należy omijać jak bozia przykazała czyli genericsami.

@pustak, tu rolę UID pełni strumień.

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