Bonjour Discovery sample (.NET)

Overview

This sample demonstrates how to use the Bonjour service discovery mechanism for both publishing and discovering services on the network. Bonjour is a facility similar to and compatible with ROZeroConf shipped with RemObjects SDK for .NET.


Prerequisites

The sample requires ZeroConf facilities Bonjour for Windows running on the host.

Getting Started

Build and launch the BonjourDiscovery server and click the button Start Server on its form to activate it. Build and launch the BonjourDiscovery client. If your server is discoverable, you will see the corresponding record in the services table view. It may take a couple of seconds for the client to discover the service. Once the service is discovered, select it and click the Use service button. Check the Communication log window below to see how the client communicates with the service. Click on the table item More to get information about the discovered service. Shut down the sample server and the corresponding service record should disappear from the list.

Examine the code

Server side

The Bonjour Discovery server is a plain RemObjects SDK server with two operations that return a welcome message and information about the service. ZeroConfRegistration is a mandatory component to register the service in Bonjour/ZeroConf service providers. To get this component to work, it is necessary to change its properties: Domain to local. and ServerChannel to the appropriate server channel.

Client side

The Bonjour Discovery client contains the ZeroConfBrowser component that is responsible for adding and removing discovered services.
First, notice the two properties of the zeroConfBrowser component that must be set properly to start the discovery:

  • Domain should be set to local.
  • Type should contain the proper service type description, _bonjourdiscoverableservice_rosdk._tcp.

There are two main events: ServiceAdded is raised when a new service is found, ServiceRemoved is raised when a service is no longer available. Examine the implementation of the handlers for these events:

private void zeroConfBrowser_ServiceAdded(object sender, RemObjects.SDK.ZeroConf.ZeroConfBrowseResultArgs args)
{
  ZeroConfService serv = args.Record;
  //Add new service to collection
  m_Services.Add(serv);
  LogMessage(String.Format("Discovered new service: {0}", serv.Name));
  //Try to resolve a domain as well as a service type and name to a real address and port.
  if (serv.TryResolve()) LogMessage(String.Format("Service resolved. Host name: {0} Port number: {1}", 
     serv.HostTarget.Replace(LOCAL_SUFFIX, String.Empty), serv.Port));
  else LogMessage("Service resolve failed!");
  SyncServicesGrid();
}

private void zeroConfBrowser_ServiceRemoved(object sender, RemObjects.SDK.ZeroConf.ZeroConfBrowseResultArgs args)
{
  ZeroConfService serv = args.Record;
  if (serv.Resolved)
    LogMessage(String.Format("Service has gone down: {0} (at host {1}:{2})",
               serv.HostTarget.Replace(LOCAL_SUFFIX, String.Empty), serv.HostTarget, serv.Port));
  else
    LogMessage(String.Format("Service has gone down: {0} (at host {1}:{2})",
               serv.Name, "'not resolved'", "'not resolved'"));
  try
  {
     List<ZeroConfService> found = m_Services.FindAll(
     delegate(ZeroConfService item)
     {
       return item.Resolved &&
       item.HostTarget.Equals(serv.HostTarget, StringComparison.OrdinalIgnoreCase) &&
                              item.Port == serv.Port;
     });
     //Remove service from collection
     foreach (ZeroConfService item in found) m_Services.Remove(item);
     SyncServicesGrid(); 
  }
  catch (Exception ex)
  {
     MessageBox.Show(this, ex.Message, "Exception occured", MessageBoxButtons.OK, MessageBoxIcon.Error);
  }
}

The following code shows how the client can create and use the selected service instance:

private void btUseService_Click(object sender, EventArgs e)
{
   ZeroConfService serv = m_Services[dgvServices.CurrentRow.Index];
   if (serv.Resolved)
   {
     // Locating and using IPv4 address as host name for compatibility with Delphi
     // servers (and possible others without IPv6 support)
     string host = serv.HostTarget.Replace(LOCAL_SUFFIX, String.Empty);
     for (int i = 0; i < serv.Addresses.Length; i++)
     {
       if (serv.Addresses[i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
       {
         host = serv.Addresses[i].ToString();
         break;
       }
     }
     clientChannel.TargetUrl = String.Format("http://{0}:{1}/bin", host, serv.Port);

     IBonjourDiscoverableService servinstance = CoBonjourDiscoverableService.Create(message, clientChannel);
     . . .
   }
}