ZpětObsahDalší

Objective C: příklad 7
Mechanismus klient/server


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

1. Protokol -- sample7.h

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

2. Implementace serveru -- sample7.m

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

3. Implementace klienta -- sample7c.m

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ětObsahDalší

Copyright (c) Chip, O. Čada 2000