For the high level Networking code, its really quite simple to send and receive packets.
The Server will register on a known port say 4500 with
NetworkServer.Listen (SERVER_PORT);
And will listen to Message Requests from Clients.
Each Message will have a known structure and will have a Message ID.
Say you have a NetworkInitializationMessage that the Cilent always sends to the Server on Connection. To Hear that message the NetworkServer must “Listen” for it
NetworkServer.RegisterHandler(INIT_MSG_ID, ReceiveNetInitMessage);
Where INIT_MSG_ID is a known number (eg 100) and ReceiveNetInitMessage is the Code to be run when that message is received.
Create a file NetMessages.cs and put all your messages in the same file and that file will exist in your client and server builds.
Messages are really simple. Create the Data Structure that you want to send and then define it as a SubClass of MessageBase (I hope I’m using the correct terminology as I’m not a C# programmer, but see Below). The MessageBase class is just a wrapper for your data.
public const short SERVER_PORT 4500
public const short INIT_MSG_ID 100
public class NetInit : MessageBase
{
public short sNetVersion;
public short sMajorVersion;
public short sMinorVersion;
public short sPatchVersion;
}
In your ServerNetworking have Send/Receive Pairs for handling communications transactions.
public void ReceiveNetInitMsg(NetworkMessage netMsg)
{
NetInit msg = netMsg.ReadMessage<NetInit>(); // Read the Incoming Message Packet.
SendNetInitMsg(netMsg.conn.connectionId, sNetVersion, sMajorVersion, sMinorVersion, sPatchVersion);
}
public void SendNetInitMsg(int nc, string sNetVersion, string sMajorVersion, string sMinorVersion, string sPatchVersion)
{
Net Init msg = new <NetInit>();
msg.sNetVersion = sNetVersion;
msg.sMajorVersion = sMajorVersion;
msg.sMinorVersion = sMinorVersion;
msg.sPatchVersion = sPatchVersion;
NetworkServer.SendToClient (nc, INIT_MSG_ID, msg);
}
CLIENT SIDE…
For the Client to Connect it needs to know the IP Address of the Server (domain name) and the port.
NetworkClient.connect(“test.myproject.org”, SERVER_PORT);
then set up listeners same as the server
NetworkClient.RegisterHandler(INIT_MSG_ID, ReceiveNetInitMessage);
and have a paid of routines for sending and receiving.
SendNetInitMsg()
{
NetInit msg = new <NetInit> ();
NetworkClient.send(INIT_MSG_ID, msg);
}
ReceiveNetIntMsg(NetworkMessage netMsg)
{
NetInit msg = new NetInit (); // Containers for incoming data.
var message = netMsg.ReadMessage<NetInit> (); // Read the incoming Message
msg.sNetVersion = message.sNetVersion;
msg.sMajorVersion = message.sMajorVersion;
msg.sMinorVersion = message.sMinorVersion;
msg.sPatchVersion = message.sPatchVersion;
}
There is also some standard messages like On Connected
NetworkClient.RegisterHandler(MsgType.Connect, OnConnected);
public void OnConnected(NetworkMessage netMsg)
{
Debug.Log ("ClientConnectionis:" + client.isConnected);
SendNetInitMsg ();
}
So in the above…
Client knows the Server Domain/Port and sends a Connection Request.
UNITY handles the connection and once its successful Client->OnConnected is returned
Our OnConnected sends a SendNetInitMessage() to the Server.
As there is already a connection open, we don’t need to worry about passing an address with the packet. Unity just says… Send a Message along this connection. All we need to say is, its Message 100 and its Structure is NetInit.
On the Server we are listening for Message 100’s and when we here one… We call ReceiveNetInitMessage which is passed a copy of the NetworkMessage as a parameter. Another REALLY useful thing for the Server is the networkMessage has the ConnectionID of the sender, so we know WHO we can send a response back to.
In this example, the Send Packet has no values in its datapacket, because the Client is asking the Server “What Version Are You”. The Receive Procedure gets the information it needs and then Sends the Response Packet back to the client “Hey I am Version X” BUT the Receive Procedure has to pass the networkconnection to the Send Response so Send response knows WHO the packet will be sent to.
The Client is listening for Messages of type 100, when it gets a response it calls ReceiveNetInitMsg, which passes a NetworkMessage with datapacket NetInit.
So the above is really good for you to be able to check that both the client and server are using the SAME NetworkMessages file… Cause if Client is talking Version 1 Packets and Server is talking Version 2 Packets… BOOM !
GENERAL INFORMATION
Clients only need 1 connection to talk with a server. But Clients can open connections to multiple servers. Say you want Registration Server, Lobby Server, Play Servers… The Client can open 3 connections 1 to each server.
Servers can have multiple connections open, and the Server will allocate a connectionID to each client (which so far) seems to persist with the connection. So in my example above, Servers can only instigate Message to the Clients if you have kept a record for each Client and their Connection ID. (I know this information is also kept in NetworkServer lists, but its poorly documented and may change so I keep my own structure for it).
In My example above. The Server Receiving Message calls the Server Sending Message, but it doesn’t need to. It could for instance call an ASYNC DB call that when returning calls the Server Sending Message, PROVIDED you send the networking connection ID along for the ride !
It doesn’t appear at the HighLevel calls that you need to serialize / deserialize data, although that may be because I am using simple structures.
Hope that Helps.
Mark