Intégrez Rendezvous dans vos applications Cocoa - Partie 2
Note de l’éditeur — Dans la première partie de cette série à plusieurs volets, Mike Beam discute des concepts qui entourent Rendezvous (ZeroConf) et de l’intégration de ces fonctionnalités à vos applications Cocoa. Aujourd’hui en seconde partie, il vous montre comment construire un client Rendezvous simple comparable à iChat.
Note du traducteur — Un point à préciser. Ce n’est que dans le dernier paragraphe de son article que Mike précise qu’il y a un bug dans Jaguar, et que son application ne marche pas si on utilise l’interface loopback, il faut absolument être sur un réseau local.
Notre Application
Aujourd’hui nous allons construire une application pour publier et lister un service Rendezvous, et dans le prochain article, je vous montrerai comment donner à vos applications la possibilité de communiquer avec d’autres instances de l’application sur le réseau.
Je me suis senti très inspiré, et j’ai décidé d’appeler cette application RCE pour Rendezvous Chat Example.
Grandiose n’est-ce-pas ?
![]() |
![]() |
|
|
Sur la gauche, nous voyons RCE désactivé ; sur la droite il est lancé et vous pouvez voir que je suis la seule personne sur mon réseau à posséder le service RCE. Prenez en compte le message d’alerte vu qu’il contient une faute d’orthographe et qu’il est bien rouge ! Beurk ! (NdT: le message dit : NE considérez PAS ceci comme un exemple “constiuant” une bonne interface utilisateur — la faute se trouvant dans “constitues” — “constiuant”). |
||
Sur la gauche vous voyez l’état de l’interface quand elle vient d’être lancée.
Le champ au sommet est où nous spécifions le nom du service que nous allons publier.
Ce champ est connecté à la classe Controller par l’outlet nameField.
Puisque il s’agit d’une application de chat, le nom du service est par défaut le nom long de l’utilisateur actuellement connecté.
Sous nameField se trouve le bouton pour démarrer et stopper le service.
Vous pouvez voir sur la droite de la vue d’écran comment le titre du bouton passe de “Start Chat Service” (Activer le Service Chat) à “Stop Chat Service” (Stopper le Service Chat) quand on clique dessus.
Ce bouton est connecté à l’action toggleServiceActivation : du Controller.
Le dernier élément de l’interface est la table “Mi Amigos” (en présumant que toutes les personnes connectées au réseau sont vos amis).
Il s’agit d’une table d’une colonne qui affiche la liste des services découverts sur le réseau.
Les noms qui apparaissent dans la table sont les mêmes que ceux spécifiés dans nameField.
Sur la droite, vous ne voyez que mon nom, puisque j’étais le seul à faire tourner RCE quand j’ai fait la prise d’écran (mon département de ventes y travaille).
L’outlet de la table est discoveredServiceList de la classe Controller.
Controller a été configuré comme une source de données pour discoveredServiceList, donc nous n’aurons pas à implémenter les méthodes NSTableViewDataSource nous-mêmes.
Implémentation de l’Application
Commençons l’implémentation de cette application. La première chose à faire est d’effectuer toute initialisation dans awakeFromNib.
Pour le moment, il n’y a vraiment qu’une chose à faire qui est d’initialiser nameField avec une valeur de départ, qui comme je l’ai dit sera le nom complet de l’utilisateur connecté.
Ce nom est obtenu en utilisant la fonction de Foundation NSFullUserName, que nous utilisons dans awakeFromNib comme cela :
- (void)awakeFromNib
{
[nameField setStringValue:NSFullUserName()];
}
La cible du bouton “Start Chat Service” est l’action du Controller toggleServiceActivation :.
Dans cette méthode nous faisons appel à certaines méthodes qui configurent différentes parties de l’application quand le service est activé, et d’autres méthodes qui font du nettoyage quand le services est désactivé.
Quand un service est activé il est nécessaire de configurer une socket, et une instance de NSNetService qui publiera notre service.
Puisque notre application publie les services et les consomme en même temps — c’est-à-dire qu’elle en fait la recherche et les utilise — nous devons également mettre en place un navigateur de services.
Ceci est le comportement habituel des applications de chat qui font à la fois une annonce de leur présence aux autres clients chat quand vous vous connectez (le côté publication de service), et affichent ceux qui se sont connectés (le côté navigateur de service).
Voici l’implémentation de toggleServiceActivation :
- (IBAction)toggleServiceActivation:(id)sender
{
switch ( [sender state] ) {
case NSOnState:
[self setupSocket];
[self setupService];
[self setupBrowser];
[nameField setEnabled:NO];
break;
case NSOffState:
[serviceBrowser stop];
[domainBrowser stop];
[service stop];
[nameField setEnabled:YES];
break;
}
}
Cette action est invoquée quand le bouton Marche/Arrêt du service est pressé.
Quand cette action est invoquée, nous effectuons un changement d’état en fonction de l’état courant.
Si l’état est NSOnState, ce qui indique que le service devrait avoir été activé, nous effectuons ce que nous avons à faire pour configurer les différents composants du service de chat, ce qui inclu la construction de la socket, la création et la publication du service associé et la mise en place du navigateur.
Enfin, nous rendons invalide le nom du champ afin d’éviter que l’utilisateur ne le modifie pendant que le service tourne.
Si l’état est NSOffState, alors nous effectuons les étapes nécessaires pour enlever le service du réseau et stopper la recherche d’autres services.
Ce que nous faisons en envoyant des messages stop aux objets NSNetService et NSNetServiceBrowser.
Après les avoir stoppés, nous devons modifier le champs texte du nom du service pour que l’utilisateur puisse le modifier s’il le souhaite.
setupSocket
Les sockets sont le sujet de l’article suivant, mais je veux les évoquer ici parce que configurer une socket est la première étape de la création et publication d’un service.
Les sockets sont, pour les programmeurs, des points de communications réseau.
Quand une connexion a été établie entre le serveur et le client, une paire de sockets y est associée : une sur le client et une sur le serveur.
Les données sont transférées du client au serveur quand le client écrit sur sa socket représentant le serveur.
Le serveur obtient les données envoyées par le client en lisant les données disponibles sur sa socket représentant le client.
La chaîne des événements est valable dans le sens opposé.
Quand un serveur démarre, il crée ce que l’on appelle une socket d’écoute.
C’est la socket qui est à “l’écoute” de demandes de connexions de la part des clients.
Une socket d’écoute est ce que nous avons besoin de configurer pour notre service réseau.
Certains pourraient considérer que NSNetService et Rendezvous ne font rien d’autre qu’annoncer la présence d’une socket d’écoute.
On a donné un nom à cette socket, celui du service, et un type, qui est celui du service discuté plus haut.
Les navigateurs à la recherche de services d’un type particulier obtiendront alors en réponse, le nom de notre service particulier, et quand le nom du service est résolu, le client récupère l’adresse et le numéro de port de la socket d’écoute du serveur auquel se connecter.
Alors vous voyez comment, d’un point de vue du programmeur, NSNetService ne fait qu’annoncer l’existence d’une socket à laquelle les clients intéressés peuvent se connecter.
NSFileHandle est utilisé pour communiquer au
moyen d’une socket.
Une fois de plus, les détails en seront discutés dans le prochain
article, mais nous allons en créer une pour setupSocket maintenant.
- (void)setupSocket
{
socketPort = [[NSSocketPort alloc] initWithTCPPort:12345];
listeningSocket = [[NSFileHandle alloc]
initWithFileDescriptor:[socketPort socket]];
}
Dans ce code, les variables socketPort et listeningSocket sont
deux variables d’instances de Controller.
Donc dans l’interface de la classe, nous devons ajouter :
NSSocketPort *socketPort;
NSFileHandle *listeningSocket;
Dans setupSocket nous effectuons deux choses.
Nous utilisons NSSocketPort pour créer une socket liée au port 12345 en utilisant la méthode d’initialisation initWithTCPPort.
A la ligne suivante nous instancions et initialisons un NSFileHandle par la méthode initWithFileDescriptor:.
Le fichier descripteur que nous passons dans cette méthode est le fichier descripteur de la socket retournée par un message socket à notre objet NSSocketPort.
Encore une fois, nous en discuterons plus dans le prochain article, en voyant également une alternative à NSSocketPort.
Cette méthode est assez simple.
NSNetService annonce l’existence de la socket que nous avons créée dans cette méthode.
Bien sûr, pour le moment, notre socket ne fait absolument rien, mais cela changera dans le prochain article.
Pour le moment, nous imaginerons que notre socket sur le port 12345 est prête pour effectuer des choses importantes qui valent la peine d’annoncer son existence à Rendezvous (bien que, comme Rendezvous est si facile à utiliser, même si le service derrière la socket est un modèle de médiocrité, cela vaudrait quand même la peine de le publier).
Chose intéressante, toute la documentation concernant Rendezvous indiquent que la création d’une socket est la première étape nécessaire pour créer un service.
En vérité nous pouvons faire l’annonce d’un service sans créer de socket.
C’est tout à fait inutile, puisque les clients ne pourront pas se connecter.
Le fait est que nous devons nous assurer que notre service fonctionne avant de le publier.
NSNetService n’effectue aucune vérification pour s’assurer qu’il existe une socket valide sur le port spécifié.
setupService
Après avoir configuré la socket nous devons configurer l’instance
de NSNetService.
Ce que nous effectuons par la méthode setupService,
présentée ci-dessous :
- (void)setupService
{
service = [[NSNetService alloc] initWithDomain:@""
type:@"_rce._tcp."
name:[nameField stringValue]
port:12345];
[service setDelegate:self];
[service publish];
}
La variable service est une autre variable d’instance qui doit être ajoutée à l’interface de la classe :
NSNetService *service;
L’initialisation d’une instance de NSNetService est effectuée par la méthode initWithDomain:type:name:port:.
Le premier argument, initWithDomain:, est le domaine dans lequel nous souhaitons enregistrer notre service.
Pour l’instant, cette classe ne supporte que l’enregistrement au domain local, .local.
Plutôt que de préciser .local comme domaine, nous passons une chaîne de caractères vide que NSNetService comprend comme “enregistre ce service dans le domaine par défaut”, qui est .local.
L’argument suivant, type, est une chaîne de caractères qui identifie le type du service et de la couche transport.
Pour ce paramètre, nous passons _rce._tcp.
L’objet NSNetService publiera notre service comme étant de type rce.
La raison pour laquelle ces éléments sont préfixés par un underscore est pour que le répondeur mDNS puisse les identifier comme des informations concernant le service, plutôt que faisant partie du nom du serveur.
(La chaîne de caractère type: fait partie d’une chaîne plus grande utilisée par le répondeur de mDNS qui contient le nom du serveur et une description du service : par exemple, Mike._rce._tcp.southpark.local.)
Dans l’argument suivant, name:, nous spécifions le nom du service.
Ce nom devrait avoir une signification pour les utilisateurs, plutôt qu’une incantation indéchiffrable de caractères que les ordinateurs aiment utiliser.
C’est en fait le nom qui apparaîtra dans la liste des navigateurs des autres instances RCE du réseau.
Nous initialisons le nom de notre service à la chaîne de caractères contenue dans le champ texte nameField.
Enfin nous spécifions le numéro de port auquel notre socket est liée.
Spécifier le numéro de port lors de l’initialisation est en fait le seul contact que NSNetService a avec les capacités réseaux de notre application.
Tout ce que NSNetService fait, c’est dire à ceux qui sont intéressés (par exemple les applications recherchant des instances de service _rce._tcp) que “je fait tourner un service sur le port 12345 et de type _rce._tcp“.
Votre service est la belle de la soirée, et NSNetService est son copain un peu éméché qui crie son nom et son numéro de téléphone à qui le demande.
NSNetService a deux types de fonctionnalités : il publie les services que nous créons, et il converti également les adresses des services découverts.
Pour ce paragraphe, nous nous intéressons à son aspect publication.
- Publication
- netServiceWillPublish:
- netServiceDidStop:
- netService:didNotPublish:
- Résolution
- netServiceWillResolve:
- netService:didNotResolve:
- netServiceDidResolveAddress:
La fonctionnalité des deux ensembles de méthodes est assez semblable, et servent à notifier le délégué du progrès des opérations de publication et de résolution, et de toutes erreurs qui pourraient survenir durant ces opérations.
Nous parlerons des méthodes déléguées de résolution par la suite, et nous disons juste quelques mots ici sur les méthodes déléguées de publication.
Chacune de ces méthodes déléguées passe en paramètre l’objet du service réseau qui a invoqué la méthode.
Dans netServiceWillPublish: et netServiceDidStop:, le seul argument est l’objet du service réseau qui a envoyé le message.
La méthode netService:didNotPublish: passe l’objet NSNetService comme premier argument, et un dictionnaire d’erreur en second argument.
Ces deux premières méthodes peuvent être utilisées
pour mettre à jour l’interface utilisateur pour qu’elle reflète
l’état de la publication du service.
Nous ne faisons rien de grandiose ici, nous imprimons juste une message sur la
sortie standard, avec NSLog, indiquant où nous
en somme de la publication, comme montré ici :
- (void)netServiceWillPublish:(NSNetService *)sender
{
NSLog( @"Publishing service %@", [sender name] );
}
- (void)netServiceDidStop:(NSNetService *)sender
{
NSLog( @"Stopping service %@", [sender name] );
}
Les objets NSNetService notifient leurs délégués d’erreurs en invoquant leurs méthodes respectives didNotPublish: ou didNotResolve:.
Des informations concernant l’erreur sont passées dans un dictionnaire d’erreurs comme dernier argument de cette méthode.
Les dictionnaires erreurs contiennent des objets pour les clés NSNetServicesErrorCode et NSNetServicesErrorDomain.
L’objet de NSNetServicesErrorDomain nous indique si l’erreur est survenue au niveau de la couche réseau mach ou dans l’objet NSNetService.
Cette information est en général moins intéressante que la constante passée pour NSNetServicesErrorCode.
Les codes erreurs possibles sont listés dans la table ci-dessous.
| Constantes | Description |
| NSNetServicesUnknownError | Une erreur indéterminée est survenue. |
| NSNetServicesCollisionError | Le service n’a pas pu être publié parce que le nom est déjà utilisé en local ou par un autre système. |
| NSNetServicesNotFoundError | Le service n’a pas pu être trouvé sur le réseau. |
| NSNetServicesActivityInProgress | Le service réseau ne peut pas exécuter cette requête pour le moment. |
| NSNetServicesBadArgumentError | Un argument invalide a été utilisé lors de la création de l’objetNSNetService. |
| NSNetServicesCancelledError | Le client a annulé l’action. |
| NSNetServicesInvalidError | Le service réseau n’a pas été correctement configuré. |
Configuration du Navigateur
C’est dans la découverte de services que Rendezvous est vraiment brillant : c’est le nec plus ultra de la simplicité, qui permet à un utilisateur, sans aucun effort, de voir s’afficher la liste des services qui lui sont disponibles.
Vous ne pouvez pas faire plus simple.
Heureusement pour nous développeurs d’applications, implémenter un navigateur de services Rendezvous est pratiquement aussi simple.
NSNetServiceBrowser accepte deux types de recherche : nous pouvons rechercher par domaines auxquels les services peuvent appartenir, et nous pouvons rechercher tous les services d’un domaine particulier.
Nous verrons les deux aspects, mais seulement le dernier est supporté par l’interface utilisateur de RCE.
Comme nous l’avons fait avec NSNetService, nous implémenterons les méthodes déléguées de NSNetServiceBrowser qui vont diriger l’interface en réponse aux événements de découverte.
Par exemple, si un service est enregistré sur le réseau, notre objet NSNetServiceBrowser notifiera son délégué, l’objet Controller, de la découverte en invoquant la méthode déléguée netServiceBrowser:didFindService:moreComing:.
Avant de passer à l’implémentation de ces méthodes déléguées,
nous allons configurer l’objet navigateur par la méthode setupBrowser.
Cette méthode est la suivante :
- (void)setupBrowser
{
if ( !serviceBrowser ) {
serviceBrowser = [[NSNetServiceBrowser alloc] init];
[serviceBrowser setDelegate:self];
}
if ( !domainBrowser) {
domainBrowser = [[NSNetServiceBrowser alloc] init];
[domainBrowser setDelegate:self];
}
if ( !discoveredServices )
discoveredServices = [[NSMutableArray alloc] init];
[domainBrowser searchForAllDomains];
[serviceBrowser searchForServicesOfType:@"_rce._tcp." inDomain:@""];
}
Premièrement nous effecutons une initialisation des objets serviceBrowser et domainBrowser :
s’ils n’existent pas encore, nous les créons, sinon nous continuons.
Nous faisons la même chose avec le tableau discoveredServices.
Ces trois objets doivent être déclarés comme variables d’instances
dans l’interface, dont voici la liste :
@interface Controller : NSObject
{
NSNetService *service;
NSNetServiceBrowser *serviceBrowser;
NSNetServiceBrowser *domainBrowser;
NSMutableArray *discoveredServices;
NSSocketPort *socketPort;
NSFileHandle *listeningSocket;
IBOutlet id discoveredServicesList;
IBOutlet id nameField;
}
.
.
.
@end
Créer une instance de NSNetServiceBrowser est aussi simple que d’invoquer alloc et init sur NSNetServiceBrowser.
A chaque création d’une instance de NSNetServiceBrowser, nous assignons self comme délégué afin que notre objet Controller puisse être alerté lors de la découverte de nouveaux domaines, services et autres événements qui peuvent survenir lors d’une recherche.
Ensuite nous faisons la même chose pour le tableau discoveredServices, qui est déclaré dans l’interface comme une variable d’instance.
Ce tableau fournira la table des services avec ses données à travers les méthodes de source de données de NSTableView que nous allons implémenter.
Enfin, nous commençons la recherche des services dans le domaine par défaut qui sont de type _rce._tcp en invoquant la méthode searchForServicesOfType:inDomain:.
Notez qu’une instance de NSNetServiceBrowser ne peut pas rechercher simultanément des domaines et des services : c’est l’un ou l’autre.
Cependant, si vous vouliez faire une recherche pour les deux en parallèle, vous pourriez le faire en ayant deux instances de NSNetServiceBrowser : une pour rechercher les domaines, et l’autre pour rechercher les services.
C’est exactement ce que nous faisons dans notre application.
Alors que la découverte de domaines et de services est supportée, seule la navigation de services est proposée sur notre interface utilisateur.
La découverte de domaine est rapportée à l’utilisateur uniquement sur la sortie standard.
Les Méthodes Déléguées de NSNetServiceBrowser
NSNetServiceBrowser déclare les sept méthodes déléguées suivantes :
- netServiceBrowserDidNotSearch:
- netServiceBrowserWillSearch:
- netServiceBrowser:didStopSearch:
- netServiceBrowser:didFindService:moreComing:
- netServiceBrowser:didRemoveService:moreComing:
- netServiceBrowser:didFindDomain:moreComing:
- netServiceBrowser:didRemoveDomain:moreComing:
Dans chacune de ces méthodes (à part les deux premières), l’objet navigateur qui a invoqué la méthode est passé en argument de netServiceBrowser:.
Pour les deux premières, l’objet navigateur qui invoque la méthode est passé comme l’argument unique.
Pour être bref, je n’écrirai plus les préfixes netServiceBrowser quand je ferai référence à ces méthodes.
Les trois premières méthodes listées ci-dessus, didNotSearch:, willSearch: et didStopSearch:, notifient le délégué du progrès ou de l’état de l’opération de recherche.
Juste avant qu’une recherche commence, une fois que l’objet navigateur est configuré correctement, qu’il a déterminé que le réseau est présent, il invoquera la méthode willSearch.
La méthode didStopSearch est invoquée au niveau du délégué en réponse au message stop envoyé à l’objet navigateur qui est en cours de recherche.
NSNetServiceBrowser a une méthode de rapport d’erreurs : netServiceBrowser:didNotSearch:.
Cette méthode passe au délégué l’objet navigateur qui rapporte l’erreur, ainsi qu’un dictionnaire d’erreur qui contient les mêmes clés que le dictionnaire d’erreurs de NSNetService décrit précédemment.
La paire de méthodes didFindService:moreComing: et didRemoveService:moreComing: est utilisée pour rapporter au délégué la découverte et la suppression de services.
Les arguments de Service: de ces méthodes sont des instances de NSNetService qui représentent le service de réseau Rendezvous qui a été découvert, ou supprimé du réseau.
Ces objets qui nous sont passés dans didFindService:moreComing: et didRemoveService:moreComing: ne sont pas les mêmes objets par lesquels les services sont publiés.
Ce sont en fait de simples instances de NSNetService qui représentent ces services comme quelque chose à quoi se connecter.
Au contraire des instances de NSNetService qui sont utilisées pour publier les services, ces objets NSNetService sont appropriés uniquement pour effectuer la résolution du service découvert.
Si vous regardez la référence de la classe NSNetService vous verrez un autre initialisateur que celui dont nous avons discuté.
Cet initialisateur supplémentaire est initWithDomain:type:name:, et il est utilisé pour initialiser les instances de résolution de NSNetService.
Notez qu’il est identique à l’initialisateur de publication que nous avons utilisé auparavant, excepté que nous ne pouvons pas spécifier de numéro de port.
Si vous tentez d’envoyer un message publish à un service réseau non initialisé par cette méthode, alors la méthode netService:didNotPublish: du délégué sera invoquée avec un NSNetServicesBadArgumentError.
Nous n’avons jamais à créer d’objets de résolution de services réseaux nous mêmes, puisque c’est NSNetServiceBrowser qui s’en occupe, mais j’ai pensé qu’il fallait le mentionner.
Typiquement, quand un service est découvert et reporté par didFindService:moreComing:, nous envoyons immédiatement un message resolve à l’objet de service réseau qui nous est passé.
Ceci permet de déterminer les informations de connexions avant qu’elles ne soient nécessaires à l’utilisateur.
Le problème est que la résolution d’une adresse et du numéro de port d’un service peuvent prendre un temps non négligeable.
Comme nous pouvons commencer le processus de résolution en tâche de fond, nous le faisons pour éviter de retarder la connexion quand l’utilisateur en fait la demande.
La dernière paire de méthodes, didFindDomain:moreComing: et didRemoveDomain:moreComing:, est utilisée pour notifier au délégué que des domaines ont été découverts, et si des domaines ont disparu.
NSNetServiceBrowser a deux méthodes pour rechercher les domaines : searchForAllDomains et searchForRegistrationDomains.
Un domaine d’enregistrement est un domaine sur lequel nous avons le droit d’enregistrer un service : .local est un domaine d’enregistrement.
Des quatre méthodes dont nous avons discuté, je dois encore mentionner l’argument de moreComing: qui est un BOOL.
Quand un service objet est en recherche, il peut recevoir en peu de temps des réponses de plusieurs serveurs faisant tourner les services.
Cependant, le navigateur de service ne peut rapporter qu’un domaine ou service découvert à la fois.
L’idée derrière le flag moreComing: est que quand le navigateur de services rapporte des services découverts, il utilise un flag pour notifier si oui ou non il y aura d’autres services à rapporter qui ont été découverts en même temps.
Quand le flag moreComing: est à NO, la méthode devrait mettre à jour l’interface utilisateur.
En vérifiant la valeur de ce flag, le délégué peut réduire le nombre des rafraîchissements d’interface, consommateurs de temps processeur, à effectuer.
Implémentons maintenant notre méthode déléguée
du navigateur de services. Comme nous n’avons pas d’interface utilisateur pour
afficher les domaines découverts, nous les écriront simplement
sur le log.
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser
didFindDomain:(NSString *)domainString
moreComing:(BOOL)moreComing
{
NSLog( @"Discovered the domain %@", domainString );
}
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser
didRemoveDomain:(NSString *)domainString
moreComing:(BOOL)moreComing
{
NSLog( @"Removing the domain %@", domainString );
}
Les services découverts seront affichés dans la table discoveredServiceList.
Les services réseaux dont les noms sont affichés dans la liste
sont stockés dans le tableau discoveredServices.
Quand un service est trouvé, il est résolu et ajouté au
tableau.
Quand un service est supprimé du réseau, il est supprimé du
tableau.
Ces opérations sont effectuées dans les méthodes didFindService:moreComing: et didRemoveservice:moreComing: montrées
ici :
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser
didFindService:(NSNetService *)aNetService
moreComing:(BOOL)moreComing
{
[discoveredServices addObject:aNetService];
[aNetService setDelegate:self];
[aNetService resolve];
if ( moreComing == NO )
[discoveredServicesList reloadData];
}
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser
didRemoveService:(NSNetService *)aNetService
moreComing:(BOOL)moreComing
{
[discoveredServices removeObject:aNetService];
if ( moreComing == NO )
[discoveredServicesList reloadData];
}
Voyez comment nous utilisons le flag moreComing dans
ces méthodes pour vérifier quand les données de la tables
sont rechargées : c’est seulement quand il n’y a plus de changement à rapporter
que nous rafraîchissons l’interface.
Remarquez également dans didFindService:moreComing: que
nous mettons self comme délégué du
service découvert.
Ceci afin que l’objet controller puisse être notifié du progrès
de la résolution du service réseau.
Par exemple, nous pouvons ajouter des implémentations pour les méthodes
déléguées de NSNetService : netServiceDidResolveAddress:, netService:didNotResolve: et netServiceWillResolve:.
La première notifie le délégué d’une résolution
d’adresse réussie, la seconde est invoquée dans le cas d’une erreur
et la troisième nous dit quand le réseau est prêt pour la
résolution.
Afin d’être complet, nous ajouterons ces simples implémentations à ces
méthodes :
- (void)netService:(NSNetService *)sender
didNotResolve:(NSDictionary *)errorDict
{
NSLog( @"Une erreur est apparue lors de la resolution %@.",
[sender name] );
}
- (void)netServiceDidResolveAddress:(NSNetService *)sender
{
NSLog( @"adresse resolue avec succes pour %@.", [sender name] );
}
- (void)netServiceWillResolve:(NSNetService *)sender
{
NSLog( @"Tentative de resolution d'adresse pour %@.", [sender name] );
}
La prochaine méthode que nous devons implémenter est netServiceBrowserDidStopSearch:.
Dans cette méthode nous effectuons deux choses : nous supprimons tous
les objets de services réseaux déjà découverts du
tableau dicoveredServices, et nous rechargeons la vue
de la table pour refléter le nouvel état du tableau discoveredServices :
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser
{
if ( aNetServiceBrowser == serviceBrowser ) {
[discoveredServices removeAllObjects];
[discoveredServicesList reloadData];
}
}
Nous avons deux objets effectuant des recherches différentes, avec le même délégué.
Puisque cette méthode sera invoquée par les deux objets quand ils reçoivent les messages stop, nous devons identifier le navigateur qui invoque cette méthode.
Si l’argument browser est l’objet serviceBrowser, alors seulement pouvons nous supprimer les services et rafraîchir l’interface.
Enfin, après tout ce travail, nous avons une application pour publier et naviguer les services Rendezvous.
Vous devriez pouvoir la compiler, la lancer et voir votre propre nom s’afficher quand vous publier le service.
Si vous avez accès à d’autres Macs sur votre réseau, essayer d’y installer une copie de cette application et lancez les.
Pour tester RCE, vous devez être connecté à un réseau pour que votre nom de service s’affiche.
L’implémentation actuelle du répondeur mDNS de Jaguar a un bug qui ne reconnaît pas l’interface loopback (à l’adresse 127.0.0.1) comme une interface de réseau valide, ce qui empêche votre service de fonctionner correctement en l’absence d’une autre interface réseau.
Comme d’habitude, le dossier du project complet est disponible ici.
En Conclusion
Le groupe travaillant sur ZeroConf dit ceci de la technologie qu’ils sont en train de développer :
Il est important de comprendre que le but de ZeroConf n’est pas seulement de simplifier les réseaux personnels, bien que ce soit certainement utile.
L’objectif à long terme de ZeroConf est de permettre la création de nouveaux types de produits réseaux, qui aujourd’hui ne seraient pas commercialement viables à cause des problèmes et des coûts d’exploitation existant dans l’installation, la configuration et la maintenance du réseau leur permettant d’opérer.
C’est une perspective intéressante qui devrait faire réfléchir les développeurs sur cette technologie.
Réfléchissez-y.
Apple dit que si vous avez un produit réseau, il devrait publier ses services par Rendezvous.
C’est là, je pense, que nous verrons Rendezvous et ZeroConf se développer : au sein des applications que nous connaissons et utilisons déjà.
Une fois que les développeurs auront goûtés à Rendezvous, alors nous commencerons à voir des applications qui étaient trop difficiles à exploiter auparavant.
Nous voyons déjà des applications de collaboration, comme le tout récent iStorm, utilisant Rendezvous.
Les applications point-à-point deviendront plus répandues.
Je pense que la finalité de tout ceci est de créer un flot d’information entre les collègues, les amis,… qui soit aussi simple d’utilisation qu’un interrupteur électrique.
Nous avons vu ici comment utiliser Rendezvous avec Cocoa.
J’espère que vous l’exploiterez.
Si Cocoa n’est pas votre truc, mais que vous préférez les applications Unix cross-plate-forme ou sur toute autre plate-forme, alors téléchargez le code source de Rendezvous et amusez vous avec — cela vaut le coup d’oeil si vous faites un peu de réseau Unix.
Vous verrez peut-être quelque chose que vous apprécierez.
Acutellement, je travaille sur un projet en parallèle pour intégrer une répondeur DNS multicast dans l’application sur laquelle je travaille au boulot.
Si tout ce déroule comme prévu (ce qui semble être le cas pour l’instant), j’écrirai un article pour partager mon expérience.
C’est un truc vraiment cool, le genre de truc que j’ai toujours imaginé que les ordinateurs devraient être capable de faire.

Textes originaux en anglais sur O’Reilly :
target=”_blank”>Incorporating Rendezvous into Your Cocoa Applications, Part 2 par Mike Beam


Chargement
Commentaires récents