Komunikační návrhové vzory Forwarder - Receiver Client - Dispatcher - Server
Komunikační návrhové vzory Komunikace Distribuované systémy Vzdálené připojování k službám Problémy Plno komunikačních mechanismů 2 nejdůležitější aspekty Zapouzdření komunikačních zařízení Transparentnost umístění Návrhové vzory Forwarder – Receiver Client – Dispatcher – Server Publisher - Subscriber
Komunikační návrhové vzory Příklad Systém pro správu počítačové sítě Monitorování událostí a zdrojů Konfigurace sítě Peer to peer komunikace mezi uzly sítě Podpora různého hardware i software Zdroj: PATTERN-ORIENTED SOFTWARE ARCHITECTURE, A System of Patterns, p. 307
Komunikační návrhové vzory Realizace Vytvoření agentů běžících na uzlech v síti Low-level mezi-procesová (IPC) komunikace Efektivnější než high-level mechanizmy Problémy Závislost na OS Závislost na síťových protokolech Omezení přenositelnosti Omezená podpora heterogenních prostředí Pozdější změna IPC mechanizmu
Forwarder - Receiver Řešení Spolupráce mezi agenty Agent figuruje jako klient i jako server, nebo oboje Zapouzdření IPC mechanizmu do samostatných komponent
Forwarder - Receiver peer forwarder receiver obsahuje aplikační logiku má potřebu komunikovat s ostatními peery zná jejich identifikaci forwarder zasílá zprávy napříč procesy poskytuje obecné rozhraní abstrakce konkrétního způsobu IPC implementuje zabalení a odeslání zprávy pamatuje si převodní tabulku jmen na fyzickou identifikaci receiver odpovídá za příjem zpráv implementuje rozbalení a příjem zprávy
Forwarder - Receiver
Příklad implementace class Message { public String sender; public String data; public Message(String sender, String rawData){ this.sender = sender; data = rawData; } } class Entry { private String destinationId; private int portNumber; public Entry(String destinationId, int portNumber ){ this.destinationId = destinationId; this.portNumber = portNumber; } public String getDestinationId() { return destinationId; } public int getPortNumber() { return portNumber; } }
Příklad implementace class Registry { private Hashtable hashtable = new Hashtable(); public void put(String key, Entry value){ hashtable.put(key,value); } public Entry get(String key){ return (Entry) hashtable.get(key); } } class Server extends Thread { Receiver receiver; Forwarder forwarder; public void run(){ Message result = null; receiver = new Receiver("Server"); result = receiver.receiveMsg(); forwarder = new Forwarder("Server"); Message msg = new Message("Server", "I am alive"); forwarder.sendMsg(result.sender, msg); } }
Příklad implementace class Forwarder { private Socket socket; private OutputStream outputStream; private String name; public Forwarder(String name){ this.name = name; } private byte[] code(Message theMsg){ /*...*/ } private void deliver(String destination, byte[] data){ try{ Entry entry = fr.reg.get(destination); socket = new Socket(entry.getDestinationId(), entry.getPortNumber()); outputStream = socket.getOutputStream(); outputStream.write(data); outputStream.flush(); outputStream.close(); socket.close(); } catch (IOException e){ /*...*/ } } public void sendMsg(String destination, Message message){ deliver(destination, code(message)); } }
Příklad implementace class Receiver { private ServerSocket serverSocket; private Socket socket; private InputStream inputStream; private String name; public Receiver(String name){ this.name = name; } private Message decode(byte[] data){ /*...*/ } private byte[] receive(){ int value; byte buffer[] = null; try{ Entry entry = fr.reg.get(name); serverSocket = new ServerSocket(entry.getPortNumber(), 1000); socket = serverSocket.accept(); inputStream = socket.getInputStream(); value = inputStream.read(); buffer = new byte[value]; inputStream.read(buffer); inputStream.close(); socket.close(); serverSocket.close(); } catch (IOException e){ } return buffer; } public Message receiveMsg(){ return decode(receive()); } }
Poznámky k implementaci adresování mělo by být pravidelné adresa nemusí nutně označovat individuální uzel, ale skupinu lze zavést dokonce hierarchii skupin obsluha vypršení času a selhání komunikace peer může dát forwarderu a receiveru odpovědi čas na reakci má se forwarder pokoušet opakovat odeslání, či hned vyvolat výjimku? rozhodutí silně závisí na užitém způsobu komunikace implementace receiveru blokující neblokující podoba překladové tabulky sdílená v každém forwarderu
Výhody a nevýhody efektivita zapouzdření meziprocesové komunikace každý forwarder zná fyzickou adresu receiveru, a tedy nemusí ji nikde dohledávat přidání nové vrstvy má zanedbatelné nároky ve srovnání s vlastní komunikací zapouzdření meziprocesové komunikace změna podkladového mechanismu komunikace nemá vliv na peery chybí podpora pro pružnou změnu rozložení peerů za běhu forwared-receiver bez překladu jmen na adresy obětujeme nezávislost na fyzických adresách za zlepšení výkonu
Client - Dispatcher - Server Řešení Vytvoření mezivrstvy mezi komunikujícími Peer-mi, resp. mezi Forwarderem a Receiverem Dispatcher komponenta
Client - Dispatcher - Server poskytuje službu, jež umožňuje klientovi používat pro identifikaci serverů jejich jména a nikoli fyzická umístění (transparentnost umístění) navíc se stará o vytvoření komunikačního kanálu mezi klientem a serverem server poskytuje služby klientům registruje se či je registrován pod svým jménem a adresou u dispatchera může se nacházet na stejném stroji jako klient, ve stejné místní síti či být dostupný přes Internet klient spoléhá na dispatchera s nalezením serveru a pro vytvoření spojení s ním nadále pak pracuje pouze s kanálem k serveru, který mu dispatcher poskytl může si za běhu prohodit roli se serverem
Client - Dispatcher - Server
Příklad implementace class Dispatcher { Hashtable registry = new Hashtable(); Random random = new Random(); public void register(String serviceName,Service service){ Vector v = (Vector) registry.get(serviceName); if (v == null){ v = new Vector(); registry.put(serviceName,v); } v.add(service); } public Service locate(String serviceName) throws NotFound{ Vector v = (Vector) registry.get(serviceName); if(v == null) throw new NotFound(); if(v.size() == 0) throw new NotFound(); int i = random.nextInt(v.size()); return (Service) v.elementAt(i); } }
Příklad implementace abstract class Service { String nameOfService; String nameOfServer; public Service(String nameOfService, String nameOfServer){ this.nameOfService = nameOfService; this.nameOfServer = nameOfServer; cds.disp.register(nameOfService, this); } abstract public void service(); } class PrintService extends Service{ public PrintService(String nameOfService, String nameOfServer){ super(nameOfService,nameOfServer); } public void service(){ System.out.println("Service "+nameOfService + " by "+nameOfServer); } }
Příklad implementace public class Client { public void doTask(){ Service s; try { s = CDS.dispatcher.local("printSvc"); s.service(); } catch (NotFound e){ System.out.println("Not available") ; } } } public class CDS { public static Dispatcher dispatcher = new Dispatcher(); public static void main(String args[]){ Service s1 = new PrintService("printSvc", "srv1"); Client client = new Client(); client.doTask(); } }
Varianty distribuované dispatchery zavádí se více dispatcherů dispatcher se po žádosti od svého klienta spojí s dispatcherem cíle, který vytvoří kanál, který je přes původní dispatcher předán klientovi klient může také kontaktovat dispatchera serveru přímo, tím ale přicházíme o transparentnost umístění komunikace spravována klientem dispatcher nevytváří spojení se serverem, ale pouze předá klientovi jeho adresu s více způsoby komunikace servery se navíc registrují s podporovanými druhy komunikace client-dispatcher-service dispatcher si pamatuje mapování služeb na implementující servery na žádost o připojení dodá nějaký server, který službu podporuje pokud je dodaný server nedostupný, dispatcher se může pokusit dodat jiný vhodný kombinace se vzorem forwarder-receiver
Výhody a nevýhody snadná zaměnitelnost serverů, flexibilita a odolnost proti selhání servery se mohou registrovat i odregistrovat z dispatchera za běhu transparentnost umístění a přesunu klienti pro vyhledání serveru nepotřebují fyzickou adresu servery lze i přesouvat, pokud nejsou zrovna využívány zhoršená efektivita komunikace nutná registrace serverů dohledávání a vytváření explicitního spojení