import java.io.*; import java.net.*; import java.util.*; /** * Trida Server definuje chovani serveru. * Server posloucha na svem portu a pripadne uskutecni spojeni s klientem. * Dale se stara o rozesilani zprav vsem klientum, kdyz nejaka zprava od jednoho klienta prijde. * Nakonec uzavre spojeni s klientem, ktery se od serveru odpojil. * * @author Jirka Krhanek * @version 2007-01-08 */ public class Server extends Thread { // port na kterem server pobezi public static final int PORT = 65535; // serverSocket pouzijeme pro navazani spojeni private ServerSocket serverSocket; // socket pres ktery se pripojuje klient private Socket socket; // HashMap nam vytvori kolekci DataOutputStreamu razenych podle klicu, tedy Socketu // To nam pomuze se vyvarovat vytvareni DataOutputStreamu ve stejny cas, kdyz chceme zapsat do streamu private HashMap output = new HashMap(); /** * Metoda main je vstupnim bodem do programu * Pouziti: java Server * * @param arg seznam argumentu z prikazove radky */ static public void main(String args[]) throws Exception { // vytvorime Server objekt, ktery automaticky zacne prijmat spojeni new Server(PORT); } /** * Konstruktor Server() ktery bude neustale poslouchat * * @param port cislo portu */ public Server(int port) throws IOException { // pouze poslouchame na porte poslouchat(port); } /** * Metoda poslouchat() se stara o prichozi spojeni * * @param port cislo portu */ private void poslouchat(int port) throws IOException { //byte ip4[] = {192, 168, 0, 111}; // IP adresa 127.0.0.1 - localhost InetAddress adresa = InetAddress.getByName("127.0.0.1"); // vytvorime ServerSocket serverSocket = new ServerSocket(port, 0, adresa); // vsem dame vedet ze poslouchame System.out.println("Posloucham na: " + serverSocket); // zatimco true, budeme drzet spojeni while(true) { // zachytime dalsi prichozi spojeni socket = serverSocket.accept(); // dame vedet ze ktereho socektu prislo spojeni System.out.println("Spojeni z: " + socket); // vytvorime DataOutputStream pro zapsani dat DataOutputStream dataOut = new DataOutputStream(socket.getOutputStream()); // dame vsem vedet ze se prihlasil novy uzivatel poslatVsem("Server: Přihlášen uživatel " + socket.getInetAddress().toString().substring(1)); // ulozime si stream do mapy output.put(socket,dataOut); // vytvorime nove vlakno pro toto spojeni new Thread(this).start(); } } /** * Metoda run() bezi jako oddelne vlakno, kdyz se vola metoda start() v konstruktoru */ public void run() { // zkouska na vyjimku try { // vytvoreni DataInputStream pro komunikaci // klient pouziva DataInputStream na psani DataInputStream dataIn = new DataInputStream(socket.getInputStream()); // pokud pravda while(true) { // precteme zpravu ze streamu String zprava = dataIn.readUTF(); // vsem dame vedet zpravu System.out.println("Posilam: " + zprava); // server posle zpravu vsem klientum poslatVsem(zprava); } } // odchyceni vyjimky catch(EOFException e) { // nejaka error zprava } // odchyceni vyjimky catch(SocketException e) { // nejaka error zprava } // odchyceni vyjimky catch(IOException e) { // vypiseme vyjimku //e.printStackTrace(); } // blok finally se vykona at dojde nebo nedojde k vyjimce finally { // dojde k uzavreni spojeni uzavritSpojeni(socket); } } /** * Metoda poslatVsem() posila zpravu vsem klientum * * @param zprava zprava k odeslani */ void poslatVsem(String zprava) { // tato akce bude synchronizovana, protoze jine vlakno muze volat metodu uzavritSpojeni() synchronized(output) { for(DataOutputStream dos : output.values()) { try { dos.writeUTF(zprava); } // odchyceni vyjimky catch(IOException e) { // vypis vyjimky System.out.println(e); } } } } /** * Metoda uzavritSpojeni() odstrani soket a s nim souvisejici vystupni stream ze seznamu. * Metoda je volana pri zruseni spojeni. * * @param socket socket */ void uzavritSpojeni(Socket socket) { // opet synchronizovano, protoze jine vlakno muze volat metodu poslatVsem() // zatimco budmeme prochazet seznam vsech vystupnich streamu synchronized(output) { // dame vsem vedet o uzavirani spojeni System.out.println("Uzavirani spojeni: " + socket); // dame vsem vedet ze se odhlasil uzivatel poslatVsem("Server: Uživatel " + socket.getInetAddress().toString().substring(1) + " se odhlásil."); // odstranime zaznam z hashMapy output.remove(socket); // zkouska na vyjimku try { // ujistime se, ze doslo k zavreni socketu socket.close(); } catch(SocketException e) { // nejaka error zprava } // odchyceni vyjimky catch(IOException e) { // vypis chyby // System.out.println( "Chyba pri ukoncovani: " + socket); // e.printStackTrace(); } } } }