Komunikace Klient/Server - 3. díl - Úprava serveru

Java Pro pokročilé Komunikace Klient/Server - 3. díl - Úprava serveru

Zdravím u poslední části této minisérie o socketech v Javě, ve které si vytváříme jednoduchou komunikaci klient/server. Dnes si server upravíme tak, aby se na něj mohlo připojit více klientů. Uděláme to pomocí vláken, takže vám doporučuji si nejdříve přečíst článek o Multithredingu v Javě, abyste pochopili, co to ta vlákna jsou, protože to zde nebudu nijak zvlášť rozebírat.

Nejdříve si vytvoříme novou privátní metodu s názvem clients.

private void clients() {

}

Třídě přidáme jeden privátní atribut ArrayList<Buf­feredReader> jménem clientBufReaders. Z konstruktoru odstraníme vše kromě inicializace serverSocketu a přidáme inicializaci clientBufReaders. Nakonec zavoláme naši novou metodu clients.

public Server() {
    try {
        this.serverSocket = new ServerSocket(8080);
        System.out.print("Spuštění serveru proběhlo úspěšně.\nČekám na připojení klienta...\n");
        this.clientBufReaders = new ArrayList<BufferedReader>();

        this.clients();
    } catch (IOException e ) {
        e.printStackTrace();
    }
}

V metodě clients si vytvoříme nové vlákno jménem acceptThread, kterému jako argument předáme rozhraní Runnable s metodou run(). V metodě run si vytvoříme zas nekonečný cyklus while.

Thread acceptThread = new Thread(new Runnable() {
       public void run() {
           while(true) {
          }
    }
});

V cyklu while si vytvoříme Socket pro klienta, jménem clientSocket. Do ArrayListu clientBufReaders si přidáme BufferedReader pro nově připojeného klienta. A vypíšeme hlášku a připojení klienta a nezapomeneme to celé zase obalit do bloku try – catch.

try {
        Socket clientSocket = serverSocket.accept();
        clientBufReaders.add(new BufferedReader(new InputStreamReader(clientSocket.getInputStream())));
        System.out.println("Klient se připojil.");
} catch (IOException e) {
        e.printStackTrace();
}

Mimo metodu run si zavoláme na acceptThread metodu start() pro spuštění nového vlákna, které jsme si vytvořili.

acceptThread.start();

Vytvoříme další nekonečný while cyklus a v něm sekci synchronized, abychom mohli z tohoto vlákna přistupovat do clientBufReaders a nedošlo k race condition. Bez synchronizace by byl problém kdyby k listu obě vlákna přistoupila ve stejnou chvíli, více o synchronizace vláken v sekci Vícevláknové aplikace v Javě.

while(true) {
        synchronized(clientBufReaders) {
        }
}

Teď už zbývá jen poslední věc a to vytvořit si for cyklus, kterým postupně proiterujeme ArrayList a pokud bude BufferedReader nějakého klienta obsahovat text, tak si ho vypíšeme.

for(BufferedReader in :  clientBufReaders) {
    try {
        if(in.ready()) {
            System.out.println(in.readLine());
        } else {
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Konečně kompletní zdrojový kód by měl vypadat takto:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Server {

    private ServerSocket serverSocket;
    private ArrayList<BufferedReader> clientBufReaders;

    public static void main(String[] args) {
        Server server = new Server();
    }

    public Server() {
        try {
            this.serverSocket = new ServerSocket(8080);
            System.out.print("Spuštění serveru proběhlo úspěšně.\nČekám na připojení klienta...\n");
            this.clientBufReaders = new ArrayList<BufferedReader>();

            this.clients();
        } catch (IOException e ) {
            e.printStackTrace();
        }
    }

    private void clients() {
        Thread acceptThread = new Thread(new Runnable() {
            public void run() {
                while(true) {
                    try {
                        Socket clientSocket = serverSocket.accept();
                        clientBufReaders.add(new BufferedReader(new InputStreamReader(clientSocket.getInputStream())));
                        System.out.println("Klient se připojil.");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        acceptThread.start();

        while(true) {
            synchronized(clientBufReaders) {
                for(BufferedReader in :  clientBufReaders) {
                    try {
                        if(in.ready()) {
                            System.out.println(in.readLine());
                        } else {
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

A tohle je konec minisérie o socketech v Javě. Pod článkem máte samozřejmě celý zdrojový kód ke stažení.


 

Stáhnout

Staženo 95x (36.26 kB)
Aplikace je včetně zdrojových kódů v jazyce java

 

  Aktivity (1)

Článek pro vás napsal Filip Stryk
Avatar

Jak se ti líbí článek?
Celkem (7 hlasů) :
3.714293.714293.714293.71429 3.71429


 


Miniatura
Všechny články v sekci
Java - Pro pokročilé
Miniatura
Následující článek
HTTPS v Javě

 

 

Komentáře

Avatar
vacullik
Člen
Avatar
vacullik:

Zdravím,
jedna připomínka, myslím, že by jsi měl synchronizovat i přidávání do kolekce clientBufReaders v metodě run(). Metoda add není samozřejmě atomická a v tomto případě je docela velká pravděpodobnost, že se zrovna při jejím vykonávání přepne kontext do main vlákna, které po připojení alespoň jednoho klienta téměř pořád do této kolekce přistupuje. Důsledek je, že se mi při přidání druhého klienta téměř vždy vyhodí výjimka o dvojím přístupu do kolekce.

Editováno 19.12.2014 2:04
 
Odpovědět 19.12.2014 2:02
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 1 zpráv z 1.