Zpět | Obsah | Další |
V sedmém příkladu se seznámíme s podporou, jakou Objective C (a Cocoa) nabízí pro mechanismus klient/server. Vytvoříme server, který bude používat služeb třídy NSMutableDictionary přesně tak, jak jsme se s ní seznámili v prvním příkladu. I klient bude implementován podobně, jako v prvním příkladu -- bude se jednat o jednoduchý program, který umožní vkládat dvojice textových řetězců <klíč, hodnota> do jednoduché databáze a vyhledávat vložené hodnoty podle klíče.
// Objective C -- příklad 7/1
//
// architektura klient/server v prostředí Objective C: služby serveru
// (vyžaduje podporu OS, příklad z prostředí Cocoa)
// pro specifikaci sady služeb je ideálně vhodný mechanismus protokolů
@protocol StringServer
// protokol obsahuje seznam zpráv -- pro ukázku použijeme pouze dvě
-(void)setObject:(NSString*)value forKey:(NSString*)key;
-(NSString*)objectForKey:(NSString*)key;
@end
// end of file
Pro specifikaci rozhraní mezi dvěma objekty je ideální mechanismus protokolů -- ty nám umožňují popsat skupinu zpráv, aniž bychom museli zároveň fixovat třídu objektu, který je bude zpracovávat (jak by tomu bylo, kdybychom chtěli použít na místě protokolu interface, jak je zvykem v C++).
Pro ukázku definujeme velmi jednoduchý protokol, který bude obsahovat pouze dvě zprávy: addKey:andValue: zapíše do databáze dvojici hodnot, a valueForKey:, která vrátí hodnotu k zadanému klíči.
// Objective C -- příklad 7/2
//
// architektura klient/server v prostředí Objective C: server
// (vyžaduje podporu OS, příklad z prostředí Cocoa)
//
// Implementace se téměř neliší od "engine" části prvého příkladu;
// to, co zůstalo beze změny, je zde uvedeno kursivou:
#import <Foundation/Foundation.h>
#import "sample7.h" // protokol
#define STOREFILE @"/tmp/sample1.data"
void main()
{
NSAutoreleasePool *pool=[NSAutoreleasePool new]; // garbage collector
NSMutableDictionary *seznam; // objekt, reprezentující dvojice řetězců: to bude náš server
id myconn;
if ((seznam=[NSMutableDictionary dictionaryWithContentsOfFile:STOREFILE])==nil)
seznam=[NSMutableDictionary new]; // nemohu-li otevřít soubor, vytvořím prázdný seznam
printf("V seznamu je %d položek\n\n",[seznam count]);
// sdělíme operačnímu systému, že server je k dispozici a že se k němu
// lze připojit pod jménem "Sample7 server". To samozřejmě musí být
// služba operačního systému; Cocoa ji nabízí prostřednictvím
// standardní třídy NSConnection. Pak server aktivujeme.
[myconn=[NSConnection defaultConnection] setRootObject:seznam];
if ([myconn registerName:@"Sample7 server"]) {
[myconn runInNewThread];
printf("Server aktivován ... klávesa 'q' jej ukončí\n");
while (getchar()!='q');
} else printf("The server is already running\n");
[seznam writeToFile:STOREFILE atomically:YES];
[pool release];
printf("hotovo\n");
}
// end of file
Implementace serveru se téměř neliší od odpovídajících rutin v prvním příkladu; povšimněme si, že jediný text který není kursivou je vytvoření "serveru" -- objektu NSConnection, a jeho inicializace.
Nejprve si vyžádáme "connection" standardní službou defaultConnection, a informuje ji o tom, že jako server bude sloužit objekt seznam. Pak server registrujeme v operačním systému pod jménem "Sample7 server" pomocí standardní metody registerName:. Ta vrací YES v případě úspěchu, nebo NO pokud se registrace nepodařila (protože již někdo pod daným jménem zaregistrován je). Zaregistrovaný server v případě úspěchu aktivujeme pomocí zprávy runInNewThread; program pak dál poběží (a bude čekat na ukončení stisknutím klávesy 'q') a server bude pracovat nezávisle na něm v druhém threadu.
// Objective C -- příklad 7/3
//
// architektura klient/server v prostředí Objective C: klient
// (vyžaduje podporu OS, příklad z prostředí Cocoa)
//
// Implementace se téměř neliší od "interface" části prvého příkladu;
// to, co zůstalo beze změny, je zde uvedeno kursivou:
#import <Foundation/Foundation.h>
#import "sample7.h" // protokol
void main()
{
NSAutoreleasePool *pool=[NSAutoreleasePool new]; // garbage collector
// id<jméno protokolu> je typ, representující obecný objekt odpovídající protokolu
id<StringServer> seznam=[NSConnection
rootProxyForConnectionWithRegisteredName:@"Sample7 server"
host:@"*"];
char buffer[512]; // vstupní textový buffer
if (!seznam) {
printf("Server není k dispozici\n");
return;
}
printf("klíč,hodnota / ?klíč / * / !\n");
// hlavní cyklus, do příkazu switch vstoupí každý zadaný řádek
for (;gets(buffer);) switch (*buffer) {
// vykřičník program ukončí
case '!': goto Konec;
// otazník vyhledá hodnotu k zadanému klíči
case '?': {
NSString *val=[seznam objectForKey:[NSString stringWithCString:buffer+1]];
if (!val) printf("Není v seznamu!\n");
else printf("> %s\n",[val cString]);
}
break;
// jinak vkládáme novou dvojici
default: {
NSString *val=[NSString stringWithCString:buffer];
// rozdělíme na dva řetězce tam, kde je čárka
NSArray *a=[val componentsSeparatedByString:@","];
// a zapíšeme do seznamu
[seznam setObject:[a objectAtIndex:1] forKey:[a objectAtIndex:0]];
break;
}
}
Konec:
[pool release];
printf("hotovo\n");
}
// end of file
Na implementaci klienta je zajímavý pouze první příkaz -- vyžádáme si spojení se serverem jménem "Sample7 server" prostřednictvím třídy NSConnection. Pak již se serverem pracujeme do detailu stejně jako s kterýmkoli jiným objektem: celý zbytek zdrojového kódu už je kursivou (tj. totožný s lokálním kódem z prvého příkladu). Opět -- jen zkuste něčeho podobného docílit v C++...
Zpět | Obsah | Další |
Copyright (c) Chip, O. Čada 2000