» »

[Java] Multi Client chat server

[Java] Multi Client chat server

javaMaster ::

Živjo,

Ponovno iščem pomoč. Sem že veliko brskal po spletu in nisem našel konkretnega odgovora. Začenjam pisat aplikacijo za chat ( kot MSN, skype,..), ki ima client in server. Mene zanima kako poteka komunikacija dveh clientov preko strežnika. Namreč na spletu je opisano kako nek client pošlje sporočilo in to strežnik pošlje vsem ostalim (Broadcast). Mene pa zanima kako bi to sporočilo poslal točno določenemu clientu. Kako server naj bi identificiral posamezne cliente in kako potem sporočilo pošlje samo enemu oz. tistemu s katerim se kot uporabnik dopisujem.

Najlepša hvala za predloge.

iggy ::

Ja rabil boš idje uporabnikov, in potem to sendaš v headerju sporočila, server prebere header, in pošlje naprej.
Hey, you're fat!

Bojevnik ::

Vsakemu clientu dodeliš id?

iggy ::

Ja, sej to bi mogu že po defaultu, kako drugače pa boš razlikoval jih med seboj?
Hey, you're fat!

javaMaster ::

Kako pa dodeliš id? Za hederje pa samo samo sporočilu prilepiš id od prejemnika tako da strežnik ve komu poslat naprej.

iggy ::

Na serverju dodeljuješ id-je ob prijavi, in vodiš pač neko tabelo z idji in podatki o uporabniku.
Hey, you're fat!

_Dormage_ ::

Če je zadeva network ne rabiš id-jev, ker boš moral za vsakega clienta na serverju odpret socket.
V osnovi je socket zgrajen iz IP-ja in porta, IP je po definiciji unique zato ga lahko uporabiš kot id clienta.
Če pišeš v javi imam mogoče nekje source primera. :)

javaMaster ::

Jaz sem si zamislil takole: Ustvaril bi HashTable v katerega bi ustavil objekt socket (povezava do clienta) in up. ime uporabnika. Ob vzpostavitvi povezave s strežnikom, client pošlje sporočilo (dataOutputStream) z up. imenom uporabnika. Tako imamo tabelo z povezavo in vemo komu pripada. Potem ko uporabnik izbere sogovornika, client pošlje sporočilo strežniku z up. imenom sogovornika. Pogledal bom po hashTable-u kateri povezavi pripada izbrano ime in nato se bo ustvarila nit (z izbrano povezavo) katera bo poskrbela za pogovor med uporabnikoma. Ali bi to delovalo ? Malce sem dolgovezil. :) Pišem pa v Javi.

Zgodovina sprememb…

_Dormage_ ::

Ja stvar bi delovala super na ta način. Lahko razmisliš tudi o bazi, kjer hraniš uporabniška imena.
Na ta način lahko shranjuješ loge pogovorov :)

javaMaster ::

A pod log misliš sam pogovor ?? Kako bi v bazo shranu cel pogovor?
To delam kot končni izdelek za programiranje (matura) mora bit top shit haha :)

_Dormage_ ::

Ja celoten pogovor lahko shraniš v bazo kot text.
Na ta način lahko kot naprimer na skypu pogledaš zgodovino pogovora z posamezno osebo.
Malček si poglej sql lite in kako se poveže z javo. Od tam naprej pa je zadeva precej enostavna.
Če še nikoli nisi delal z podatkovnimi bazami potem ti ni treba komplicirat..Mogoče kasneje kot dodaten feature ko bo osnova končana :)
Vso srečo pri maturi 8-)

technolog ::

Ah dej, ne kompliciri za maturo :)

Veš kaj sem jaz delal. En program, ki zna rešit sudoku & jih generirat. Bil je super projektek, na koncu sem zgeneriral celo knigo sudokujev v PDF.

Dobil sem pa slabšo oceno nekdo, ki je predstavil zgodovino facebooka :'( Voila, več kot se trudiš, slabš je.

arjan_t ::

ne komplicirat za oceno, kompliciraj da se naučiš nove stvari

_Dormage_ ::

arjan_t je izjavil:

ne komplicirat za oceno, kompliciraj da se naučiš nove stvari

+1

javaMaster ::

Ja, z bazami sem že delal. Za zdej je samo main funkcija to da se lohko dopisuješ. Tisto šminkarijo bom že pole delal.
Veš kaj sem jaz delal. En program, ki zna rešit sudoku & jih generirat. Bil je super projektek, na koncu sem zgeneriral celo knigo sudokujev v PDF.


Cool.Lani sem tuhtal kakšn je algoritem za preverjat če upišeš pravo cifro ma mi ni ratalo pogruntat. Sošolc je tud naredu sudoku haha.

Vso srečo pri maturi

Hvala :)

_Dormage_ ::

Sudoku se lepo reši z algoritmom sestopanja (če se ne motim je to pravilni slovenski izraz).
Vbistvu je "izboljšava" brute forca.

technolog ::

Tako, in sem imel končan program in vse v enem popoldnevu, sam pol izdelava spletne strani in poročila mi je pa vzelo ogromno, ker imajo tiste butaste zahteve (koliko tabel, grafov)...

Rekel sem zato, da se ne muči preveč, ker si v letu ko pišeš maturo že itak preveč obremenjen, pa se raje potrudiš pri slovenščini in drugje, ker infe/računalništva ti ne bo problem met 5, če se spoznaš.

javaMaster ::

Rekel sem zato, da se ne muči preveč, ker si v letu ko pišeš maturo že itak preveč obremenjen, pa se raje potrudiš pri slovenščini in drugje, ker infe/računalništva ti ne bo problem met 5, če se spoznaš.

Književnost... bo še veselo ;((.

Hvala za predloge.

javaMaster ::

Živjo,

Jaz socket-te shranjujem v hashtable. Ampak ko jih želim pobrat iz hashtable za nadalno uprabo mi vrne napako, da je povezava prekinjena. Shranim pa z metodo put. Poznate še kakšen način za shranit socket. Poberem pa ga takole:
Socket socket = (Socket) seznam.get(upIme);

infiniteLoop ::

Namig - za shranjevat sockete raje uporabi kot Hashtable uporabi ConcurrentHashMap, ki je non-blocking. Za shranjevat loge bo dober tudi cisto navaden file - ni neke sile zraven "stulit" se bazo.

Problem s prekinjenimi socketi nima veze s shranjevanjem.
None of us is as dumb as all of us.

javaMaster ::

Aha, bom pogledal ConcurrentHashMap.

Problem s prekinjenimi socketi nima veze s shranjevanjem.

Hmmm, je malo čudno, ker preden jih dam v hashtable delujejo potem pa ko jih želim pobrat ven pa se prekini povezava.
Edina možnost je recimo, da namesto sockete shranjujem ip-je in porte. Ko želim povezavo z clientom preberem ip in port in ponovno povežem (nisem pokusil - govorim na pamet).

vojko20 ::

Boljše je če uporabiš HashMap (ali pa concurent hash map) z generiki, recimo HashMap<String, Socket> (string je ključ, recimo ip, socket pa povezava s uporabnikom), da ohraniš type safety.

Mogoče ti socket doživi kakšen read/write timeout. Ko se ti socket naredi nastavi timeout s funkcijo setSoTimeout na ene pol ure http://download.oracle.com/javase/1.4.2... .

Drugače bo pa lažje če prilimaš mal kode, recimo tisti del, ko se klient priklopi, ko shraniš socket v hashmap in ko ga ven vzameš.

Drugače pa ja seminarska za maturo ... Sem dobil isto oceno za spletni portal + forum v phpju (vse sam napisal), kot nekdo, ki je skopiral program.

javaMaster ::

Mogoče ti socket doživi kakšen read/write timeout.

Hmm, to pa prvič slišim. Bom poskusil to z timeout.
odseki kode:

server.java
// pripravimo strežnik, da posluša na vratih 1000.
		ServerSocket ss= new ServerSocket(port);
	System.out.println("poslušam na portu:"+ ss.getLocalPort()+"in deluej an naslovu: "+ss.getInetAddress());

	Socket socket;
	
	
while(true){ // neskončna zanka namenjena vzpostavljenju povezav
	System.out.println("sem v zanki");
	
//		vzpostavimo povezavo z clinet-om
		socket=ss.accept();
		System.out.println("sem mimo accepta");
	
		
//		Nekaj informacij za uporabnika strežnika.
		if (socket.isConnected()){
			
//		odpremo vhodni tok za izmenjavo sporočil in jih tudi preberemo, če je povezava vzpstavljena. Prejet String je uporabniško ime sogovornika.
			
		DataInputStream dis= new DataInputStream(socket.getInputStream());
		String upIme=dis.readUTF();
		System.out.println("Vzpostavil sem povezavo z: "+upIme+ " preko vrat: "+ss.getLocalPort());
		System.out.println("info o povezavi: "+socket);
		
//		povezavo in up. ime shranimo v HashTable. Tako vemo komu pripada določena povezava (socket).
		
			upo.seznamUporabnik(socket, upIme);
			System.out.println("sem mimo klica metode seznam uporabnik");

// Ustvarimo novo nit, ki skrbi za pogovor oz. izmenjavo Stringov.					
			new pogovor(socket).start(); 		
	}

		}


uporabnik.java
static Hashtable seznam = new Hashtable();

	public void seznamUporabnik (Socket povezava, String client ) throws Exception{
		
//		Shranimo v HashTable
	seznam.put(client, povezava);
	
	System.out.println("v seznam vstavljam povezavo"+povezava+" z imenom "+client);
	}
	
	public Socket najdiUpo (String upIme) throws IOException{
		Socket povezava = new Socket();
		
//		Ta metoda je klicana kadar žželimo iz HashTable seznam pobrat Socket povezavo. Kliče jo class kjer je nit za pogovor.
		
		if (seznam.contains(upIme)){
		Socket socket = (Socket) seznam.get(upIme);
		
		System.out.println("Izbrana je bila povezava"+socket);
		
		povezava= socket;
		}
			
		return povezava;
	
			}

vojko20 ::

Prilepi še od razreda pogovor del, kateri skrbi za izmenjavo podatkov (socket read in write) med klientom in serverjem.

timeout lahko dodaš v server vrstica od vrstice 17 naprej

primer:

       socket=ss.accept();
        System.out.println("sem mimo accepta");
     
         
//      Nekaj informacij za uporabnika strežnika.
        if (socket.isConnected()){
           socket.setSoTimeout(1800000); // milisekunde

Zgodovina sprememb…

  • spremenilo: vojko20 ()

javaMaster ::

Jaz imam 2 povezavi. 1. povezava je od tistega, ki štarta pogovor (ta izbere sogovornika - ta deluje). Potem pa moram iz hashtable (upIme, socket) pobrat povezavo od sogovornika. Zdej mi vrže error. Ubistvi mi počrni vrstico, kjer želim dobit stream (inputsream ali outputstream). Sem pa dodal setSoTimeout.

to je pogovor.java

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Enumeration;


public class pogovor extends Thread {


	Socket povezava2;
	Socket povezava1;
	static DataInputStream dosClient;	
	String ime=null;
	Enumeration e = uporabniki.seznam.elements();
	
	
	public pogovor (Socket povezava){
//   	preberemo ime sogovornika, pokličemo metodo najdiUpo v classu uporabnik in s ukazom get dobimo povezavo (socket) sogovornika v hashtable in to shranimo v spremenjivko
		try{
		 		System.out.println("sem v razredu pogovor");	
		 		
		 		povezava1=povezava;
		}
		catch (Exception e){
			System.out.println();
			
		}
	}
	
// tukaj se zažene nit za pogovor
	public void run ()  {
		
		try{
			
	 		while (true){	
	 		System.out.println("sem v zanki za ime sogovornika");	
	 			dosClient = new DataInputStream(povezava1.getInputStream());
	 				 ime =dosClient.readUTF();
	 				 System.out.println("ime sogovornika je: "+ime);
	 			
	 				 
	 				 while(e.hasMoreElements()){
	 		 			  System.out.println(e.nextElement());
	 		 			 System.out.println(uporabniki.seznam.size());
	 		 		  }
	 				 
	 				 if (ime != null){
	 					 
	 					povezava2 = uporabniki.najdiUpo(ime);
	 					 System.out.println("imam povezavo sogovornika: "+ povezava2);
	 					 break;
	 				 }
	 		}
	 		
	 		
	 		  
			
			
// inicializiramo DataInputStream in DataOutputStream.
	 		  	
			DataInputStream dis1=new DataInputStream(povezava1.getInputStream());
			DataOutputStream dos1 = new DataOutputStream(povezava1.getOutputStream());
			DataInputStream dis2=new DataInputStream(povezava2.getInputStream());
			DataOutputStream dos2 = new DataOutputStream(povezava2.getOutputStream());
			
			System.out.println("pogovarjate se uporabnikom (pov1)"+povezava1+" in "+povezava2);
			
			
			while(povezava1.isConnected() || povezava2.isConnected()){

// preberemo kar je napisal prvi clinet in shranimo v spremenljivko in to pošljemo drugemu client-u.
			
			String poved1=dis1.readUTF(); 
			
			dos1.writeUTF("client 1 pravi: "+poved1);
			
// preberemo kar je napisal drvi clinet in shranimo v spremenljivko in to pošljemo prvemu client-u.
			
			String poved2=dis2.readUTF();
			
			dos2.writeUTF("client2 pravi: "+poved2);
		
			}
			
			System.out.println("nekdo je koncal pogovor");
			dos1.writeUTF("konec pogovora");
			dos2.writeUTF("konec pogovora");
			povezava1.close();
			povezava2.close();
			dos1.close();
			dos2.close();
			dis1.close();
			dis2.close();
	
			
		}
			catch(IOException e){
			e.printStackTrace();
		}
	}

	
	
}

Spura ::

Tle notr je vse od tehnicnih napak, do designerskih napak, niti Java naming standardov se ne drzis (imena classov z malo).

vojko20 je izjavil:

Boljše je če uporabiš HashMap (ali pa concurent hash map) z generiki, recimo HashMap<String, Socket> (string je ključ, recimo ip, socket pa povezava s uporabnikom), da ohraniš type safety.


Hashtable ima tudi generike. In Hashtable je threadsafe, HashMap pa ni.

Zgodovina sprememb…

  • spremenil: Spura ()

javaMaster ::

Tle notr je vse od tehnicnih napak, do designerskih napak, niti Java naming standardov se ne drzis (imena classov z malo).

Kakšnih tehničnih napak ? To je samo "prototip", da vidim če zamisel deluje.


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[JAVA] HTTPS client

Oddelek: Programiranje
173049 (1779) peterv6i
»

[JAVA] zaustavitev niti (threadov)

Oddelek: Programiranje
223046 (3046) morbo
»

[java] Kako v memoriji pretvoriti String objekt v File objekt ? - neka metoda ga zaht

Oddelek: Programiranje
132050 (2050) infiniteLoop
»

[Delphi] client server

Oddelek: Programiranje
61185 (1044) jvolk
»

Kako pošiljanje datotek v JAVI.

Oddelek: Programiranje
141729 (1600) kopernik

Več podobnih tem