Unity3d server auto discover, LAN only
Asked Answered
B

2

5

I need to implement a game with a server in a local network, with no Internet access.

Provided that I can handle the connections and network communication between clients and server if they are connected, I'd like to know if there's a elegant way to make clients discover server's address at startup.


I'm providing my approach as an answer, in order to share the knowledge, but it would be nice to see if there is a more elegant/automatic approach.

Blub answered 19/4, 2013 at 17:9 Comment(1)
Alexandre, I'm pretty sure that's the only way. It's one of those things Unity "uselessly forgot to include, that you need every time"Snotty
B
7

Clients will use a specific port to connect to the game server. I implemented a UDP multicast in a different port so clients can get server's IP.

The following code is for both server and client, written in Unity Javascript. On the server side, it will start sending multicast messages every second at port 5100. Clients will listen to the same port, until they detect a new message. Then they identify sender's IP and establish a client-server connection the Unity3d way.

private var server_port : int = 5000;
private var server_ip : String;

// multicast
private var startup_port : int = 5100;
private var group_address : IPAddress = IPAddress.Parse ("224.0.0.224");
private var udp_client : UdpClient;
private var remote_end : IPEndPoint;

function Start ()
{
    // loaded elsewhere
    if (station_id == "GameServer")
        StartGameServer ();
    else
        StartGameClient ();
}

function StartGameServer ()
{
    // the Unity3d way to become a server
    init_status = Network.InitializeServer (10, server_port, false);
    Debug.Log ("status: " + init_status);

    StartBroadcast ();
}

function StartGameClient ()
{
    // multicast receive setup
    remote_end = IPEndPoint (IPAddress.Any, startup_port);
    udp_client = UdpClient (remote_end);
    udp_client.JoinMulticastGroup (group_address);

    // async callback for multicast
    udp_client.BeginReceive (new AsyncCallback (ServerLookup), null);

    MakeConnection ();
}

function MakeConnection ()
{
    // continues after we get server's address
    while (!server_ip)
        yield;

    while (Network.peerType == NetworkPeerType.Disconnected)
    {
        Debug.Log ("connecting: " + server_ip +":"+ server_port);

        // the Unity3d way to connect to a server
        var error : NetworkConnectionError;
        error = Network.Connect (server_ip, server_port);

        Debug.Log ("status: " + error);
        yield WaitForSeconds (1);
    }
}

/******* broadcast functions *******/
function ServerLookup (ar : IAsyncResult)
{
    // receivers package and identifies IP
    var receiveBytes = udp_client.EndReceive (ar, remote_end);

    server_ip = remote_end.Address.ToString ();
    Debug.Log ("Server: " + server_ip);
}

function StartBroadcast ()
{
    // multicast send setup
    udp_client = UdpClient ();
    udp_client.JoinMulticastGroup (group_address);
    remote_end = IPEndPoint (group_address, startup_port);

    // sends multicast
    while (true)
    {
        var buffer = Encoding.ASCII.GetBytes ("GameServer");
        udp_client.Send (buffer, buffer.Length, remote_end);

        yield WaitForSeconds (1);
    }
}

Attaching this to your GameObject should do the trick.

Blub answered 19/4, 2013 at 17:9 Comment(1)
BTW here's a nice long explanation of same ... answers.unity3d.com/questions/571052/… Great code AlexandreSnotty
A
4

Here is a c# version Thanks

using System.Collections;
using UnityEngine;
using System.Net.Sockets;
using System;
using System.Net;
using System.Text;

public class OwnNetworkManager : MonoBehaviour
{

private int server_port = 5000;
private string server_ip;

// multicast
private int startup_port = 5100;
private IPAddress group_address = IPAddress.Parse("127.0.0.1");
private UdpClient udp_client ;
private IPEndPoint remote_end ;


void Start()
{
    // loaded elsewhere
    if (Loader.IsPC)
        StartGameServer();
    else
        StartGameClient();
}

void StartGameServer()
{
    // the Unity3d way to become a server
    NetworkConnectionError init_status = Network.InitializeServer(10, 
server_port, false);
    Debug.Log("status: " + init_status);

    StartCoroutine(StartBroadcast());
}

void StartGameClient()
{
    // multicast receive setup
    remote_end = new IPEndPoint(IPAddress.Any, startup_port);
    udp_client = new UdpClient(remote_end);
    udp_client.JoinMulticastGroup(group_address);

    // async callback for multicast
    udp_client.BeginReceive(new AsyncCallback(ServerLookup), null);

    StartCoroutine(MakeConnection());
}

IEnumerator MakeConnection()
{
    // continues after we get server's address
    while (string.IsNullOrEmpty(server_ip))
        yield return null;

    while (Network.peerType == NetworkPeerType.Disconnected)
    {
        Debug.Log("connecting: " + server_ip + ":" + server_port);

        // the Unity3d way to connect to a server
        NetworkConnectionError error ;
        error = Network.Connect(server_ip, server_port);
        Debug.Log("status: " + error);
        yield return new WaitForSeconds (1);
    }
}

/******* broadcast functions *******/
void ServerLookup(IAsyncResult ar)
{
    // receivers package and identifies IP
    var receiveBytes = udp_client.EndReceive(ar, ref remote_end);

    server_ip = remote_end.Address.ToString();
    Debug.Log("Server: " + server_ip);
}

IEnumerator StartBroadcast()
{
    // multicast send setup
    udp_client = new UdpClient();
    udp_client.JoinMulticastGroup(group_address);
    remote_end = new IPEndPoint(group_address, startup_port);

    // sends multicast
    while (true)
    {
        var buffer = Encoding.ASCII.GetBytes("GameServer");
        udp_client.Send(buffer, buffer.Length, remote_end);

        yield return new WaitForSeconds (1);
    }
}
}
Alarum answered 6/3, 2018 at 10:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.