# Connecting to the AR 51 System (C# API)

How **AR51.Net** finds the AR 51 server, stays connected, and shuts down cleanly.

## How the client connects

1. **Discovery.** By default, `StartAsync` finds the AR 51 server automatically: it sends a **UDP broadcast on port 1500** on every network adapter, and the server answers.
2. **Registration.** The client connects to the server's registration service (**TCP port 1501**) and learns where every other service runs.
3. **Services.** Skeletons, objects, cameras, calibration and recording run on the AR 51 machines on **ports the system assigns**. These ports aren't fixed — which is why connecting through [`AR51Client`](/docs/sdk-api/csharp-api/classes/ar51client/) (which looks them up for you) is recommended.

The client **reconnects by itself** when a server restarts or the network drops, and detects a silently dead server within seconds. Recovery takes about as long as the server takes to come back, plus 1–2 seconds (`ReconnectDelay` and `DiscoveryTimeout`, 1 second each by default).

## Connect to a fixed host

If discovery can't reach the server — another subnet, a VPN, a firewall blocking UDP broadcast, or a container or WSL 2 network that doesn't pass broadcasts — give the server's address:

```csharp
await using IAR51Client ar51 = AR51Client.Create(new AR51ClientOptions { Host = "192.168.1.20" });
```

[`AR51ClientOptions`](/docs/sdk-api/csharp-api/classes/ar51clientoptions/) also sets the ports and timings; the defaults work for a standard AR 51 installation:

<div className="apiTable">

| Option | Default | What it does |
|---|---|---|
| `Host` | `null` | The AR 51 server's host name or IP address. `null` finds it automatically. |
| `RegistrationPort` | `1501` | Port of the registration service, used with `Host`. |
| `DiscoveryPort` | `1500` | UDP port used to find the server. |
| `DiscoveryTimeout` | 1 second | How long to wait for an answer to one discovery attempt. |
| `ReconnectDelay` | 1 second | Pause between connection attempts after a failure or a lost connection. |

</div>

## Wait for the connection — with a limit

`StartAsync` completes once connected. With an unreachable server it **keeps trying**, so give it a token with a timeout. Cancelling only stops the *wait*: the client keeps connecting in the background until `StopAsync` or dispose.

```csharp
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(15));
try
{
    await ar51.StartAsync(timeout.Token);
}
catch (OperationCanceledException)
{
    Console.WriteLine("No AR 51 server found within 15 seconds.");
}
```

## Follow the connection state

`State` is `Disconnected`, `Connecting` or `Connected`. `ConnectionStateChanged` is raised on a background thread, in order, whenever it changes:

```csharp
ar51.ConnectionStateChanged += (_, e) => Console.WriteLine($"Connection: {e.PreviousState} -> {e.State}");
```

## Logging

Pass an `ILoggerFactory` to see what the client does — connecting, reconnecting, refused requests. Console logging needs the `Microsoft.Extensions.Logging.Console` package:

```bash
dotnet add package Microsoft.Extensions.Logging.Console
```

```csharp
using var loggerFactory = LoggerFactory.Create(logging => logging.AddConsole());
await using IAR51Client ar51 = AR51Client.Create(loggerFactory: loggerFactory);
```

## Receive only what you need

`StartAsync` starts every live stream. If your app needs only skeletons, stop the object stream. A stream you stop **stays stopped across automatic reconnects** — until you call its own `StartAsync`, or `ar51.StartAsync()` again, which starts every stream:

```csharp
await ar51.StartAsync();
await ar51.ObjectDetection.StopAsync();   // skeletons keep arriving
```

## Shut down cleanly

Create **one** client and keep it for the life of your application. `StopAsync` stops every stream and disconnects; the client can be started again. Disposing (`await using`, or `DisposeAsync`) also stops everything and closes every connection.

## Security

:::warning[AR 51 has no authentication or encryption]
The AR 51 system doesn't check who connects, and traffic isn't encrypted. **Any computer on the same network can read the data and use every call** — including quitting servers, recording, changing camera settings and running calibration.
:::

- **Keep the AR 51 machines on their own isolated network**, and connect only trusted computers to it.
- **Gate control actions in your own app.** If your dashboard is used by people who shouldn't stop tracking or change cameras, check permissions in your app before calling those methods.
- **Don't expose the AR 51 network to the internet.** To show data remotely, relay it from your own server (see [Relay to a web front end](/docs/csharp-api/app-integration/#relay-to-a-web-front-end)) and secure that server as usual.

## Two ways to connect

| | `AR51Client` (recommended) | A standalone `SkeletonClient` or `ObjectDetectionClient` |
|---|---|---|
| Finds the server | Yes, automatically (or from a host you give) | No: you give the service's host and port |
| Follows the server if it restarts or moves | Yes | Reconnects to the same address only |
| Gives you | Everything: skeletons, objects, servers, cameras, calibration, recording, devices | One live stream |
| Use it when | Almost always | You know the service's address and need only that stream |

Servers, cameras, calibration, recording and devices are available only through `AR51Client`, because they span several AR 51 machines.

## Complete sample

Connect to a given host (or discover the server), follow the connection state, log, limit the wait, and shut down cleanly. Run it with `dotnet run -- 192.168.1.20`, or without an argument to use discovery. It also needs the `Microsoft.Extensions.Logging.Console` package.

{/* SAMPLE:02-connection — generated from the ar51-net-samples repo; edit there */}
```csharp title="Program.cs"
// Connect to a given host (or find the server), follow the connection state, log, and shut down cleanly.
// Usage: dotnet run -- [host]
using AR51.Net;
using Microsoft.Extensions.Logging;

using var loggerFactory = LoggerFactory.Create(logging => logging.AddSimpleConsole(o => o.SingleLine = true).SetMinimumLevel(LogLevel.Information));
var options = new AR51ClientOptions { Host = args.Length > 0 ? args[0] : null };   // null = automatic discovery

await using IAR51Client ar51 = AR51Client.Create(options, loggerFactory);

// Raised on a background thread, in order, whenever the connection changes: Connecting, Connected, Disconnected.
ar51.ConnectionStateChanged += (_, e) => Console.WriteLine($"Connection: {e.PreviousState} -> {e.State}");

using var quit = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) => { e.Cancel = true; quit.Cancel(); };

try
{
    // Waits until connected. With an unreachable server it keeps trying, so limit the wait.
    using var timeout = CancellationTokenSource.CreateLinkedTokenSource(quit.Token);
    timeout.CancelAfter(TimeSpan.FromSeconds(15));
    await ar51.StartAsync(timeout.Token);
    Console.WriteLine($"Connected to {ar51.ServerEndPoint}. The client reconnects by itself if the server restarts. Ctrl+C to quit.");

    await Task.Delay(Timeout.Infinite, quit.Token);
}
catch (OperationCanceledException) when (!quit.IsCancellationRequested)
{
    Console.WriteLine("No AR 51 server found within 15 seconds. Check the network, or pass the server's address: dotnet run -- 192.168.1.20");
}
catch (OperationCanceledException)
{
    // Ctrl+C
}

await ar51.StopAsync();   // optional: DisposeAsync (at the end of 'await using') also stops everything
Console.WriteLine("Stopped.");
```

[View this sample on Bitbucket](https://bitbucket.org/ar51/ar51-net-samples/src/main/02-connection/) — clone the [samples repository](https://bitbucket.org/ar51/ar51-net-samples) to run it.
{/* /SAMPLE */}

## Reference

[`AR51Client`](/docs/sdk-api/csharp-api/classes/ar51client/) · [`AR51ClientOptions`](/docs/sdk-api/csharp-api/classes/ar51clientoptions/) · [`IAR51Client`](/docs/sdk-api/csharp-api/classes/iar51client/) · [`SkeletonClient`](/docs/sdk-api/csharp-api/classes/skeletonclient/) · [`ObjectDetectionClient`](/docs/sdk-api/csharp-api/classes/objectdetectionclient/)
