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.
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.
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);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With