I was excited to see that just as I was getting ready to start my first networked multiplayer Unity project, Unity was releasing their new Unet networking APIs. “What great timing!”, I thought. However, I was a total noob when it comes to working with sockets and communicating over a network and after playing around with Unet’s HLAPI (High-Level API) it quickly became clear to me that I’d have to dive deeper to get the functionality that I was looking for. So I began to read the documentation for the LLAPI (Low-Level API) which was not pleasant at all. After seeking advice and guidance from everyone I found shake down I managed to get everything working, connecting, and sending messages to and fro.
So here is my tutorial on working with Unity’s Unet LLAPI in C# for networking noobs. There are 4 main parts to any socket networking setup, opening a socket, connecting to another socket, sending messages and receiving messages:
Starting a “Host” (or Opening a Socket)
First make a new Unity project, 2D or 3D, it doesn’t matter for this tutorial. Then add an Empty GameObject to the scene and name it Transport. Then add a new C# script to the object and open the script.
We’re going to setup our socket right as the application begins so let’s begin in the Start() method. First thing we want to do is call initialize on the NetworkTransport class (don’t forget to add using UnityEngine.Networking to the class):
public void Start() { NetworkTransport.Init(); ...
Next we just follow Unity’s documentation and add the ConnectionConfig. For most situations using the default config is fine, so let’s just go with that:
... ConnectionConfig config = new ConnectionConfig(); ...
Up next we need to add a channel and keep the channelId handy so we can use it later for sending/receiving. To do this we’ll add an int member variable to the class (not just the Start() method). We’ll also use the QosType of Reliable when setting up our channel. You don’t really need to know what this means right now (read: I don’t know enough about what this means and I still survive):
int myReliableChannelId; // above Start() ... myReliableChannelId = config.AddChannel(QosType.Reliable); // within Start() ...
This next part pretty much just sets the max number of connections allowed on your soon to exist socket:
... int maxConnections = 10; HostTopology topology = new HostTopology(config, maxConnections); ...
and finally we open the socket. One of the main stumbling blocks when trying to understand the LLAPI based on Unity’s documentation is that many thing are just named poorly. For starters, there is NetworkTransport.AddHost(). This doesn’t actually add a “Host” like the HLAPI does. This command actually just starts up a socket, I’m pretty sure they should change the name of the method to AddSocket, but who am I?? When we start the socket we have to tell it which port to listen to and in this case we use port 8888. Also the AddHost() method returns an int which is the “HostID” but screw that name we’re going to call it what it is, a SocketId. This SocketId also has to be accessible from other methods in this class so let’s put it up with the channelId:
int socketId; // above Start() int socketPort = 8888; // Also a class member variable ... // back in Start() socketId = NetworkTransport.AddHost(topology, socketPort); Debug.Log("Socket Open. SocketId is: " + socketId); } // closing curly for Start()
And with that we have our code which sets up a socket! It’ll run right away when you click the Play button in Unity. You should see the debug message appear in the console, probably with the socketId of 0. It’s not that cool yet but we’re getting there.
Connecting to the socket
Once our socket is open we use it to connect to another socket, typically on another device. We can worry about getting another device in the mix later. For now, let’s just write our Connect() method.
int connectionId; ... public void Connect() { byte error; connectionId = NetworkTransport.Connect(socketId, "localhost", socketPort, 0, out error); Debug.Log("Connected to server. ConnectionId: " + connectionId); }
We need to keep the connectionId available to all methods because later we’ll use it to send messages. NetworkTransport.Connect() … connects us to another server (Hey! They did a proper job naming that one!). We pass in our socketId, the ip for the remote device (in this case we’re just connecting with ourselves, like a long weekend alone in the woods), the socketPort of the remote machine (same as ours in this case), 0 (I forget what this is but whatever), and if there is a problem we get an error out.
The Unity documentation mentions that we can check the error with:
if (error != kOk) // wat?
But I have no idea what kOk is and judging by all the red squiggles it certainly isn’t a byte. If you know what kOk is please tell someone (preferably me) we need to figure this out people! Basically, I just include the out error parameter because I have to.
I used my Android phone as the remote device but you can use another computer if you have one available. But for now you can do most of your testing by connecting to your own socket (I’m sure there is a rude joke in there).
Lastly, go into Unity and add a UI button and set the OnClick event to fire off our Connect() method. If you don’t want to do that I suppose you can just call Connect() at the end of Start() after our code that adds the socket. That would be good enough for now if you don’t want to make the button.
Sending a Message!
Finally (half of) the thing we actually want to do! Here we turn a string into a stream of bytes then send those bytes out our socket connection.
public void SendSocketMessage() { byte error; byte[] buffer = new byte[1024]; Stream stream = new MemoryStream(buffer); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, "HelloServer"); int bufferSize = 1024; NetworkTransport.Send(hostId, connectionId, myReliableChannelId, buffer, bufferSize, out error); }
Quick run down: Declare another (unused) byte variable called error. Create byte array called buffer and set it’s length to 1024 (this is the max length of our message when it is in byte form). The next 3 lines do the conversion from string to byte array. I don’t know the details about it, but it works, so it’s good enough. We also send over the size of our buffer byte array as an int (which is bufferSize). Lastly we put all the stuff together, starting with out class variables hostId, connectionId, and myReliableChannelId then adding the rest.
Now that we’ve got our SendSocketMessage() method you can go back into Unity and add a UI button to fire off the method on the buttons OnClick event.
Listening for NetworkEvents (or Receiving a Message)
Last part! We can send a message to other connected devices but now we have to make our application do something when it gets these messages. Otherwise we’re just shouting into the void. We need to always be checking for new messages coming in so this portion is added to the Update() method.
void Update() { int recHostId; int recConnectionId; int recChannelId; byte[] recBuffer = new byte[1024]; int bufferSize = 1024; int dataSize; byte error; NetworkEventType recNetworkEvent = NetworkTransport.Receive(out recHostId, out recConnectionId, out recChannelId, recBuffer, bufferSize, out dataSize, out error); ...
All we’re doing is declaring all the variables we need then setting up a NetworkTransport.Receive() method. Almost all those variables are assigned as a result of a message being received (all the parameters that begin with out). The recBuffer contains the byte array message that was received, while recNetworkEvent is an enum with 4 possible event types:
- Nothing – When no messages are received.
- ConnectionEvent – A socket connection is made.
- DataEvent – A message is received.
- DisconnectEvent – A device that was connected as told us it is closing the connection.
We’re going to use these event types to decide what to actually do with the messages we receive. So we’re going to continue to add on to our Update() method with a big ol’ switch statement:
... switch (recNetworkEvent) { case NetworkEventType.Nothing: break; case NetworkEventType.ConnectEvent: Debug.Log("incoming connection event received"); break; case NetworkEventType.DataEvent: Stream stream = new MemoryStream(recBuffer); BinaryFormatter formatter = new BinaryFormatter(); string message = formatter.Deserialize(stream) as string; Debug.Log("incoming message event received: " + message); break; case NetworkEventType.DisconnectEvent: Debug.Log("remote client event disconnected"); break; }
So based on the type of network event we have a few different debug messages display. With the event type Nothing we do… nothing. This message comes in every Update() that a message of some other type is not received so we can ignore it. With ConnectionEvent we just want to be notified of the connection, but in a game you might do something like load a player prefab or display some text that a new player has connected.
DataEvent is the real meat and potatoes. This is where a message is received from a connected device and our application has to do something based on that message. Since our SendSocketMessage() method currently only sends a string we’ll only include code to handle string messages received (it’ll still try to convert any bytes into a string, so if you send something other than a string you’ll get an error or a garbage string (probably? Didn’t try it.)).
You can see that in the DataEvent case we’re doing almost the same thing as we did in the SendSocketMessage() method but instead of making a string into bytes, now we’re making bytes into a string. Once the message is back in a string form we display it as part of a debug message. Bam! Message Received!
Lastly there is the DisconnectEvent type. I don’t do anything with that event type here except log it to the console but you can image using this event as the time to do things like remove a player’s prefab, or display a disconnect message on screen.
Try it out
That should be all you need to get up and running. You have an application that, on startup, makes a socket available for connections. With the press of your Connect button the application uses it’s socket to connect to another device’s socket. Pressing your Send Message button will blast a string message from your socket to the remote devices socket and the remote device will receive the message, unpack it and display it in the console.
I did my testing initially just having my computer running Unity connect to it’s own socket, just as a way to rapidly test things. Because of this I saw the connect message in the console 2x, since one event was made for each side of the connection. After I got everything working like this, I changed the “localhost” to my computer’s IP address then built the project and sent it to my Android phone. I would then run the application in the Unity editor so I could see the console and I used the app on my phone to connect and send the message. It was really rewarding to hit the Send Message button on my phone and see the message appear in Unity’s console on my PC!
Expanding
This post is already super long, but I just want to give some final thoughts and extra tips.
How do I use this to make a game?
You can have another switch statement that executes different methods or series of methods based on the message received. So getting a message like “ChangeToNight” can trigger a method that changes the time in your game environment.
Does the message have to be a string?
No! It can be any object, all you have to do is serialize the object in a similar way to how we serialized the string. For instance I have experimented with sending JSON messages so that I can transport more complex objects. Using JSON .NET for Unity made this super easy.
Where can I read more about sockets?
While trying to figure all of this out I was directed to Beej’s Guide to Network Programming. It’s pretty advanced, written for C++ and I didn’t read much of it, but the What is a socket? section helped clear up some of my confusion about sockets.
I hope this helps some people who want to dive into Unity’s new networking API but don’t know a thing about network programming prior. If you are an experienced network programmer and have noticed things that I am wrong about, or things that could be expanded upon please let me know and I’ll update this guide.
Amazing article! Really helpful, thanks a lot 🙂
I still haven’t been able to connect a client and a server on the same computer (localhost) on my own. Not sure whats wrong, but I will keep trying using info from this article.
QoS is Quality of Service, pretty much what guarantees there are on message arrival. Reliable just means that the message will get to the other side at some point.
kOk should be NetworkError.Ok, not sure where you got kOk from.
Also, take a look at BuildPipeline, you can write an editor script to have a second play button that automatically builds the client and the server separately and runs them, so that you can ship them separately. (So that the client doesn’t get a copy of the server)
Thanks! I’m glad you like it and thanks for the tips. I saw that there was QoS types of Reliable and Unreliable, which I assume is similar to a TCP and UDP, respectively. The kOk came from this Unity blog post from last year, before Unet was released http://blogs.unity3d.com/2014/06/11/all-about-the-unity-networking-transport-layer/ . Thanks for telling me about BuildPipeline. It looks like it’s just what I need!
You’re having trouble connecting two applications? Make sure that you do the entire Starting a “Host” (or Opening a Socket) section on both the “Client” and “Server” application before attempting to start a connection from either one. That was one thing I had trouble with at first, understanding that in this setup, neither application was technically a “client” or “server” it’s more like two equal applications talking to each other. Let me know if that helps!
No problem 🙂
The BuildPipeline goes very well with the Scripting Define Symbols, you can write Client and Server code together and separate them using macros, for example:
private int channelreliable;
private byte error;
private string address = “localhost”;
private int port = 14158;
private int hostid;
#if SERVER
private const int maxPlayers = 32;
#else
private int clientid;
#endif
void Start()
{
GlobalConfig gc = new GlobalConfig();
NetworkTransport.Init(gc);
ConnectionConfig cc = new ConnectionConfig();
channelreliable = cc.AddChannel(QosType.Reliable);
#if SERVER
HostTopology ht = new HostTopology(cc, maxPlayers);
#else
HostTopology ht = new HostTopology(cc, 1);
#endif
hostid = NetworkTransport.AddHost(ht, port, address);
#if !SERVER
clientid = NetworkTransport.Connect(hostid, address, port, 0, out error);
#endif
}
Yes thats my connection code, I am not sure why it does not work.
Now that you tell me that AddHost is actually AddSocket, I believe that my problem is that the HostTopologys are not the same.
I should open one host for every client right? Damn thats so misleading, lol.
Also you can use these methods to write yourself a cool buildscript:
BuildPipeline.BuildPlayer(new String[]{}, “/Users/bleh/Documents/whatever”, BuildTarget.StandaloneOSXIntel64, BuildOptions.Development|BuildOptions.AutoRunPlayer);
and
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, “SERVER”);
Heres the method I use to handle errors:
if ((NetworkError)error == NetworkError.Ok)
{
//it’s alright (continue doing stuff)
}
else Debug.LogError(“Error: ” + (NetworkError)error); //not good
By the way, Unity tells me that localhost is an invalid IP. I tried using 127.0.0.1 instead and it gives me a different error. Wierd, I thought localhost == 127.0.0.1.
I’m going to try having a ‘host’ for every client, thanks for pointing that odd quirk out! Its kind of strange that they label it a ‘host’ if it only supports one connect, and both sides have a host, lol.
I assume I will have to rewrite my packet handling to check multiple hostids, and have an array of hostids. Do you think it is safe to identify players by the hostid?
so is this more like p2p rather than server/client? if so would you know how to make a server/client application in respect, i was looking at a way to do authoritive server for unity to run the headless linux mode, but no luck atm =/
Well P2P does not really exists ; there is always, at the lowest, someone having an open socket and someone else connecting to it.
You can use that to do autoritive server ; easy way as two separated Unity projects ; a server and a client one. Server project Will be launched headless and process every autoritative computation it should.
Hey, thanks for the runthrough. I’m having a similar problem as the other guy — I’m running on PC and when I launch the executable from build and run it will talk to itself just fine, and when I launch from the editor it will talk to itself just fine, but if I launch more than one at a time the second instance gets a negative return from NetworkTransport.AddHost call, and that’ll cause it to throw errors when you attempt to connect or send a message.
I thought that might be from a conflicting port, so I added a check to see if the hostId was negative and try again on a different port. This makes it so that two instances can run at the same time, but they’re still just talking to themselves, not to each other. I feel like I’m missing something obvious! Any thoughts on how to get them to talk to each other instead of themselves? (By the way, I’m connecting to 127.0.0.1 instead of localhost, if that’s relevant at all.)
+1 I’m having the same problem. Did you ever figure out how to solve this problem?
Nope. I gave up and switched to Lidgren.
You’re trying to make two hosts on the same socket, which won’t work because it’s already being occupied by the first instance. One program needs to run as the host, and with that host id the second instance can connect
I get an error saying stream, BinaryFormatter, BinaryFormatter and Serialize do not exist. Do I need to include using something?
You need at the top of your C# file:
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
Good article! But has 2 things missing:
– All of this is required, not just the Networking
using UnityEngine.Networking;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
– NetworkTransport.Send(hostId, connectionId, myReliableChannelId, buffer, bufferSize, out error);
Here you use hostId even though you declared it socketId, can be confusing.
My 2 cents. Thanks for the article really helpfull 🙂
Thanks !
QoS Reliable is used when speed is less important; QoS Unreliable is faster, but according to Captain Obvious, might have flaws.
Would you happen to have any example code using the JSon Serializer? I got the JSon asset you recommended, but I’m having difficulty getting the syntax correct to implement it in your method — Thanks, great article!
Sure thing! First import the plugin in your project, it’ll create a new folder.
After that add
using Newtonsoft.Json;
to the top of your class that’s doing the message sending/receiving.
at this point the only thing you have to do is use:
JsonConvert.SerializeObject(object) to convert your object into a string. Then serialize the string to the binary format and send it off just like above.
so the code would look like:
Character character = new Character();
string stringifiedCharacter = JsonConvert.SerializeObject(character);
On the receiving end use:
JsonConvert.DeserializeObject(string) after converting the binary data into a string to turn the string back into the typed object that you originally stringified from. Example:
Character destringifiedCharacter = JsonConvert.DeserializeObject(string);
Hope this helps!
Thanks, much! Although, I guess I had the correct syntax after all. Turns out the problem is a persistent SocketID of -1 OR SocketID of 0 combined with a “Wrong IP address or Port” warning. It doesn’t seem to matter what I use — I’ve tried various ports and used my computer’s explicit IP instead of “localhost” but nothing seems to work. I even tore everything down and tried a simple test with the example from the article, cut and pasted verbatim, but I can’t get a valid connect. I suppose it could be the same problem that Ryan and Rodol had. If anyone has a suggested fix, I’d love to hear it.
I think the socketID of -1 issue is a result of trying to run 2 game clients on the same machine. Is this what you are doing? Could you try using the computer explicit IP address and running one of the clients on a different machine?
Yes, I was running 2 game clients on the same machine. This isn’t a problem with other methods, but I could see how it could potentially cause the conflicting port issue here. I have to tackle some other issues over the next few days, but I’ll try your recommendation when I can and get back to you, thanks!
Well, I revisited and found the problem — in the connectionID function call, I never replaced “local host” with ipID — Doh!! Pretty obvious when you see it, but it took me a while because of the way I had written the program. Thanks again!
I got the Json deserializer working as well, but when I tried to send data in both directions, I ran into a hitch — The only way I could make it work was to build two transport objects with 2 separate scripts and 2 open sockets with one socket open to device #1 and one socket open to device #2. Maybe I was assuming I could send data 2 ways via this method because other networking methods permit it, but I was unable to. Anyone know if I’m missing something?
Changing “localhost” to “127.0.0.0” in the NetworkTransport.Connect call worked for me.
I did everything in this tutorial and it works. I’m trying to send a whole class instead of just a string
[System.Serializable]
public class DataTraveller
{
public int food;
public int water;
public DataTraveller(int f, int w)
{
food = f;
water = w;
}
}
public void SendSocketDataTraveller(int socket, int connId, int channel, DataTraveller message)
{
byte error;
byte[] buffer = new byte[1024];
Stream stream = new MemoryStream(buffer);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, message, null); // Added the null trying to remove header but with no sucess
Debug.Log (buffer[0]);
int bufferSize = 1024;
NetworkTransport.Send(socket, connId, channel, buffer, bufferSize, out error);
}
and I get an error when receiving client side, saying there is an header conflict between Network_Server and DataTraveller. Any hints on how to solve this?
hi i hav a question
in the HLAPI, unity offer host(server+client), server only, client only, how do i achieve that with LLAPI?
when i use LLAPI to connect unity editor locally on my PC, 2 calls will receive after connection has been make, one is with connectionId 1 and another is connectionId 2
can i assume that one of them is the server connection, and the other is the client connection from the unity editor, which resulting a host situation? if that s the case, how can i tell which connection is the host.client , and which is the host.server connection?
I noticed that too. I added a debug.Log in the ConnectEvent in the Update(), and when i press connect I get 2 events for id 1 and id 2. I verified this by adding each connection of a list and printing the count out. why is this? My code looks good.
Yo! Can somebody help me send/receive Position of a player with LLAPI, please?
I have client which sends some data to the server I want that data to be sent to other clients. How should I do that ? Please help!
Thanks for writing this! It was very informative. I am working on a top-down shooter game and need an optimized networking solution with client side prediction, lag comp etc. For anyone else looking at the Unity Low level API, I strongly suggest thinking about using UDP sockets directly: https://msdn.microsoft.com/en-us/library/system.net.sockets.socket(v=vs.110).aspx
There are some excellent articles here on how to use UDP for games here http://gafferongames.com/networking-for-game-programmers/
The examples are in C++, but combined with the MSDN documentation it’s not too hard to figure out – I am a noob when it comes to network programming (and C# for that matter) and didn’t have too much trouble. Even if you decide not to go that route, the background is still useful to have in mind.
I had trouble getting the unity LLAPI to work (although while refactoring I found the bug in my code that caused me problems), and found that when I just did things from scratch with the sockets my network code actually got a bit smaller! Unity’s LLAPI is not particularly well documented and this blog post is one of the few guides on how to use (so good work on that!).
Hey I hav some problems.. when i click on connect button which links with connect method it gives me erro like:
NetworkManager detected a script reload in the editor. This has caused the network to be shut down.
UnityEngine.Networking.NetworkIdentity:UNetStaticUpdate()
And if I call Connect method on send of Start() then it works for me…
Also when i use “localhost” as ip it gives me error so i have to place there 127.0.0.1
it also gives me warning that :
NetworkManager detected a script reload in the editor. This has caused the network to be shut down.
UnityEngine.Networking.NetworkIdentity:UNetStaticUpdate()
The scriptingmanual says that kOK is the message given out if everything is fine
Hi!
How would one send a message that exceeds the length of 1024 bytes? I guess the maximum should be 1024 to prevent the connection from hogging all the bandwidth. But how would one send an object or a string that is bigger than 1024 bytes? Do you have to chop the byte array up in to multiple sequences of 1024 bits and send each array in a separate Send call? If that is the case how would one glue these all together again on the server side? Would you need to manually add a stop bit and look in the byte array for a stop bit or sth like that in order to reconstruct the serialized object?
I guess you could just use the QoS ReliableFragmented to do this without any additional implementation?
You would use (int)stream.Position as your buffer size. In fact the way he does it here is wrong.
I managed to make it works! Thanks! I really don’t like the Hlapi system of unity, I have the sensation that I’m not on control of things. Making simple tcp connections will be a lot a of work, but I will have all controls, that HLapi, Photon and others don’t offer to me.
I think I will make a server with java or php, to make it work on linux, but right now are just thoughts.
The buffersize should not be fixed to 1024 bytes when sending. It should be calculated from the stream with (int)stream.Position
A struggle a lot to solve this functionality, so here you are:
Put it on separete empty gameobjects
///////////////////////////////////////
server:
///////////////////////////////////////
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
public class Network_Controler : MonoBehaviour
{
public Text Txt1;
public int myReliableChannelId;
public int socketId;
public int socketPort = 8888;
public int connectionId;
void Start()
{
NetworkTransport.Init();
Connectar();
}
public void Connectar()
{
ConnectionConfig config = new ConnectionConfig();
int maxConnections = 5;
config.AddChannel(QosType.UnreliableSequenced);
HostTopology topology = new HostTopology(config, maxConnections);
socketId = NetworkTransport.AddHost(topology, socketPort);
//byte error;
//connectionId = NetworkTransport.Connect(socketId, “192.168.1.141”, socketPort, 0, out error);
//Txt1.text = Txt1.text + “SockId: ” + socketId + “ConnId: ” + connectionId + “-” + error.ToString();
}
void Update()
{
//Recibo del cliente
int recChannelId;
byte[] recBuffer = new byte[1024];
int bufferSize = 1024;
int dataSize;
byte error;
NetworkEventType networkEvent = NetworkTransport.Receive(out socketId, out connectionId, out recChannelId, recBuffer, bufferSize, out dataSize, out error);
switch (networkEvent)
{
case NetworkEventType.Nothing:
break;
case NetworkEventType.ConnectEvent:
Txt1.text = Txt1.text + “incoming”;
break;
case NetworkEventType.DataEvent:
Stream stream = new MemoryStream(recBuffer);
BinaryFormatter formatter = new BinaryFormatter();
string message = formatter.Deserialize(stream) as string;
Txt1.text = Txt1.text + message;
break;
case NetworkEventType.DisconnectEvent:
Txt1.text = “Disconnected”;
break;
}
}
public void SendSocketMessage()
{
byte error;
byte[] buffer = new byte[1024];
Stream stream = new MemoryStream(buffer);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, “Hello del Server “);
int bufferSize = 1024;
NetworkTransport.Send(socketId, connectionId, myReliableChannelId, buffer, bufferSize, out error);
// Txt1.text = socketId.ToString() + connectionId.ToString() + myReliableChannelId.ToString() + buffer.ToString() + bufferSize.ToString() + error.ToString();
}
}//Clase
/////////////////////////////////////////////////////////////////////////////
Client
/////////////////////////////////////////////////////////////////////////////
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
public class Network_Client : MonoBehaviour {
public int port = 8888;
public Text Txt1;
private HostTopology topology;
private ConnectionConfig config;
private int recConnectionId;
private int hostId;
private int recChannelId;
void Start()
{
NetworkTransport.Init();
config = new ConnectionConfig();
config.AddChannel(QosType.UnreliableSequenced);
topology = new HostTopology(config, 5);
hostId = NetworkTransport.AddHost(topology, port);
byte error;
recConnectionId = NetworkTransport.Connect(hostId, “192.168.1.139”, port, 0, out error); //Llamo al server
}
void Update()
{
byte[] recBuffer = new byte[1024];
int bufferSize = 1024;
int dataSize;
byte error;
NetworkEventType networkEvent = NetworkTransport.Receive(out hostId, out recConnectionId, out recChannelId, recBuffer, bufferSize, out dataSize, out error);
//Txt1.text = “IdS” + hostId + ” IdC=” + recConnectionId;
NetworkError networkError = (NetworkError)error;
//Txt1.text = hostId +”-” + recConnectionId + “-” + recChannelId.ToString() + “-” + recBuffer.ToString() + “-” + bufferSize.ToString() + “-” + dataSize.ToString() + “-” + “Error:” + “-” + networkError;
if (networkError != NetworkError.Ok)
{
//Txt1.text = “>” + hostId + recConnectionId.ToString() + “-” + recChannelId.ToString() + “-” + recBuffer.ToString() + “-” + bufferSize.ToString() + “-” + dataSize.ToString() + “-” + “Error:” + “-” + networkError;
}
switch (networkEvent)
{
case NetworkEventType.Nothing:
break;
case NetworkEventType.ConnectEvent:
Txt1.text = Txt1.text + “incoming”;
break;
case NetworkEventType.DataEvent:
Stream stream = new MemoryStream(recBuffer);
BinaryFormatter formatter = new BinaryFormatter();
string message = formatter.Deserialize(stream) as string;
Txt1.text = Txt1.text + message;
break;
case NetworkEventType.DisconnectEvent:
Txt1.text = “Disconnected”;
break;
}
}
public void SendSocketMessage()
{
byte error;
byte[] buffer = new byte[1024];
Stream stream = new MemoryStream(buffer);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, “Hello Cliente”);
int bufferSize = 1024;
NetworkTransport.Send(hostId, recConnectionId, recChannelId, buffer, bufferSize, out error);
}
}//Clase
Hello,
Could someone please help me. I have executed the code in the same instance of my unity game and it works perfectly. But I’m having trouble getting it to work with two separate games. I can even connect. Any help is appreciated.
This is the first script :
—————————
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
using UnityEngine.Networking;
public class TransportLayer : MonoBehaviour {
// Use this for initialization
void Start () {
// Initializing the Transport Layer with no arguments (default settings)
NetworkTransport.Init();
}
// Update is called once per frame
void Update () {
int recHostId;
int connectionId;
int channelId;
byte[] recBuffer = new byte[1024];
int bufferSize = 1024;
int dataSize;
byte error;
NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
switch (recData)
{
case NetworkEventType.Nothing: //1
break;
case NetworkEventType.ConnectEvent: //2
Debug.Log(“Connect Event”);
break;
case NetworkEventType.DataEvent: //3
Debug.Log(“Data Event”);
break;
case NetworkEventType.DisconnectEvent: //4
Debug.Log(“Disconnect Event”);
break;
}
}
}
——————————-
This is my second script :
——————————-
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
using UnityEngine.Networking;
public class TransportLayer : MonoBehaviour {
int myReliableChannelId;
int hostId;
int connectionId;
// Use this for initialization
void Start () {
byte error;
// Initializing the Transport Layer with no arguments (default settings)
NetworkTransport.Init();
ConnectionConfig config = new ConnectionConfig();
myReliableChannelId = config.AddChannel(QosType.Reliable);
HostTopology topology = new HostTopology(config, 10);
hostId = NetworkTransport.AddHost(topology, 8888);
connectionId = NetworkTransport.Connect(hostId, “192.168.1.6”, 8888, 0, out error);
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (“space”)) {
Send ();
}
}
void Send(){
byte[] buffer = new byte[1024];
int bufferLength = 1024;
byte error;
Stream stream = new MemoryStream(buffer);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, “testing”);
NetworkTransport.Send(hostId, connectionId, myReliableChannelId, buffer, bufferLength, out error);
}
}
Good article – to answer your question about the kOk, a better way would be to use the enum…
public void SendSocketMessage()
{
byte error;
var bytes = System.Text.Encoding.UTF8.GetBytes(“Hey hey”);
NetworkTransport.Send(hostId, connectionId, channelId, bytes, bytes.Length, out error);
NetworkError nwError = (NetworkError)Enum.Parse(typeof(NetworkError), error.ToString());
if(nwError != NetworkError.Ok)
{
Debug.Log(“Error occurred – ” + nwError.ToString());
}
}
Not sure why every single post on the Internet about Unity sockets involves having a unity host and unity client. In most cases one would only need a client, where server is elsewhere written in another technology
So true 🙂 but still a great starting place!
Not when you’re trying to make a quick game in a short period where the client wants multiplayer functionality and doesn’t want to spend money to build a dedicated server, nor do you want to pay for Unity’s matchmaking. The host/client duality is pretty useful in those cases.
Great tutorial, but one thing: You don’t explain the variable “HostId” in the “Sending a Message!” section, where it should be declared or what should be in it. Earlier in the tutorial you said that what the api refers to as a host id should really be called socket id, but in this step you list them as two different variables. The only comment I see about your “hostID” variable here is something about it being an out variable, which seems incorrect, as that parameter is not marked “out” in the call.
Hello! I have a question, let us suppose that we have few clients, each one has its own main scene and there is going to be a Transport gameObject on every scene, so does that mean that every Transport script will launch its Start method? in this case how can they connect to each other?
Thank’s so much for writing this article. I wanted to cry this morning but now I feel like this is something that maybe I can do. Relief!
I see you don’t monetize robotmonkeybrain.com, don’t waste your traffic, you can earn extra cash every
month with new monetization method. This is the best adsense alternative for any type of website (they approve all sites), for more details simply search in gooogle:
murgrabia’s tools