Networking - MasterServer [ Connect on Lan or Wan without Internet ]

I’ve started to building my own multiplayer game for iOS, and It’s coming together slowly but surly.

The multiplayer game is to be locally ran, so people on the same WLAN can only play it. But every time I create a closed network, I get an error ‘Cannot connect to MasterServer’.

After doing some research it turns out that when you create a multiplayer game, you’re actually using a Server somewhere in Unity HQ, thus needing a continues connection to the Internet.

Is it possible to use one of the iOS devices to use as a server, as well as play the game? I assumed I was already doing that, but I guess not.

Anyway, is this possible? Reason is, firstly I wont need a connection to Internet (so WLAN will work fine), and I also read that the MasterServers are really for testing only, as they are unreliable.

Any suggestions? Thanks

Hi,

This is going to take a bit more out of u than you could actually think. First thing is for 2 system or device to connect to, you need ipadress of one another or atleast the ipadress of the host is needed by every client that wish to connect to.
I have to tell my presence to everyone on the network. There are 2 ways(as I know) to tell others that I am here

1 - one way is by using a dedicated server to which i would be polling my ipaddress continously, and that dedicated server would act as a medium and give my presence to others who send their presence to the sever. This way the server would act as a medium and let others know that there is someone called flamy waiting to play from so and so address. This is a simple task. This is wat masterserver actually does. Now since it is a simple task, it comes with a limitation, you have to keep running this master server locally for others to connect to, which is highly annoying and sometimes impossible. Also the ip address of master server changes, it has to be changed in code or config file or similar. [Note: Unity provides master server source for free, you can just download it and install in one of your servers or on cloud and use it for production as well, but that is not gonna help u much if the game has to run in local.]

2 - Other way is a bit different and would be handy for you. I can keep telling everyone in the network that I am here regardless of who is listening, that way others who are on the same network would be able to know your presence if they want to look for others presence. This is cannot be done only with Unity3d classes. You need to use a technique called UDPBroadcast. This can be done using .Net framework.

So for UDPBroadcasting what has to be done is, Connect to a port on local in my machine and send certain message continuously to a remote port at certain intervals. And the remote machine will connect to the “remote port”, u have sent the information to and get the information.
(you can imagine port as a virtual point where data is exchanged. IF i send a data to port 100 to ipadress xxx.xxx.x.xx, only the guy who expects data from 100 will receive it.)

using System.Net.Sockets; use this and create 2 UDP client instances, one for sending messges and one for receiving (using one is also fine but btr done seperately.)

            UdpClient sender;

            int remotePort = 19784;

         void Start()
         {
            
			sender = new UdpClient (localPort, AddressFamily.InterNetwork);
			IPEndPoint groupEP = new IPEndPoint (IPAddress.Broadcast, remotePort);
			sender.Connect (groupEP);
			
			//SendData ();
			InvokeRepeating("SendData",0,5f);
		
         }
    void SendData ()
	{
		string customMessage = myName+" * "+myIP+" * "+myGameName;
				
		if (customMessage != "") {
			sender.Send (Encoding.ASCII.GetBytes (customMessage), customMessage.Length);
		}

	}

In start I am connecting to a remote port and start invoking send data after certain time (5 seconds). In send data function I am creating a parsed message including my name , ip, game name seperated by " * " note that you can use xml tags (i usually seperate like flamy ) or parser or any seperator to identity data uniquely on other end. If you have noted this line " IPEndPoint groupEP = new IPEndPoint (IPAddress.Broadcast, remotePort); ", this is what makes you send data to every connected system in network.

if still it is not clear, the strategy here is to use UDP broadcast to send my ipaddress to other and let them connect to my system using Network.Connect(); (Note: Network.connect needs ipadress of host to connect to, this udp is providing the ipaddress of the host i need the most.) and after they connect i am going to shut down this udpBroadcast thing and continue with unity only. But Until I connect, UDP is gonna be my friend.

And once sending is done I have to receive it, it is a bit more complicated and has some restrictions. Firs thing is receiving is gonna be a asynchronous process, so it will be run in a separate thread out of unity’s main thread. So in this asynchronous method, you cannot use unity’s static variables/methods. If used would through an error. But this can be handled easily. Well now you know the restriction, check the method to get a clear idea.

UdpClient receiver;
    
    public void StartReceivingIP ()
	{
		try {
			if (receiver == null) {
				receiver = new UdpClient (remotePort);
				receiver.BeginReceive (new AsyncCallback (ReceiveData), null);
			}
		} catch (SocketException e) {
			Debug.Log (e.Message);
		}
	}
    private void ReceiveData (IAsyncResult result)
	{
		receiveIPGroup = new IPEndPoint (IPAddress.Any, remotePort);
		byte[] received;
		if (receiver != null) {
			received = receiver.EndReceive (result, ref receiveIPGroup);
		} else {
			return;
		}
		receiver.BeginReceive (new AsyncCallback (ReceiveData), null);
                string receivedString = Encoding.ASCII.GetString (received);
	}

Now parse this received string, you will have more than necessary things to connect to a server. So everyone should call StartReceivingIP (). and when you create server, you should stop receiving IP and be calling sendData().

I hope I am not confusing. Hope this would work fine for you.

Oh wait I forgot to tell you something, this will work only if the first 3 parts of the ipAdress are same 192.168.1.x and 192.168.1.y they can see each other but not 192.168.2.X well no need to worry in a same wireless netwrk, everyone will have the same address family, unless multiple routers are involved in the network. Well this aint a blocker, this can be handled. Check .Net reference when needed, I dont want to confuse by going into all that networking stuff. cheers.

PS: .Net socket class support has been removed for unity3d free licenses for Mobile versions, so UDPBroadcast wont work on iOS, android or Windows Phone Free licenses. (source: Bunny83)

Just to complement Flamy’s awesome answer…

Just TBC, this can help say during debugging or if your app is only used, say, internally by devs:

in the SERVER just use Network.player.ipAddress to get your IP address. Show it on the screen

in the client, let the human user just type that in.

the librays you need
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Net;
using System.Linq;
using System.Text;