- Home /
Unity UDP freezes if disconnected from server
Here is the code :
private String sendString(string message)
{
try
{
//if (message != "")
//{
//Sending data to client--->
byte[] data = Encoding.UTF8.GetBytes(message);
int re = client.Send(data, data.Length, remoteEndPoint);
//Receiving data from client--->
byte[] recv = client.Receive(ref remoteEndPoint);
//Debug.Log("Received from " + remoteEndPoint.Address.ToString());
String result = System.Text.Encoding.UTF8.GetString(recv);
//Debug.Log (result + " " + remoteEndPoint.Address.ToString());
return result;
//}
}
catch (Exception err)
{
print(err.ToString());
return "false";
}
}
This works fine as long as the app is connected to the server. But as soon as it is disconnected from the server, the game freezes. Can someone please help with this?
EDIT: I have found out that client.Receive causes the problem. Because as soon as I remove the receive part, it does not freeze even after the client is disconnected.
Answer by WazzaM · Mar 30, 2018 at 03:26 AM
Hello @nikrath
UDP doesn't make connections. The remote host is reachable or not. When you call client.Receive()
you're blocking the current thread while it waits to get a message on the UDP port. Because the thread is blocked, Unity is starved and can't make updates - so it freezes.
You need to call Select() before doing the receive to check if any data is available on the port, then read the port if there is - this is the basis for non-blocking I/O.
You could try doing the read in another thread but that's also not great because that thread will block - unless you do Select() first - and that just causes things to come to a grind.
Hope that helps.
Regards Warwick
@Wazza$$anonymous$$ Thanks for the answer. But what module does the Select function come under? I have checked and there is no such thing as client.Select(). Which Select function are you referring to?
Hi @nikrath
Select is part of the .NET standard in System.Net.Sockets.
See https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.select(v=vs.90).aspx
You'll need to add using System.Net.Sockets;
to the top of your script and then call Socket.Select(...) to make the call. You should be able to do this from your script's Update()
method.
Select() indicates when a socket is readable, writable and has an error. Don't worry about the error and in real-world cases you don't need to worry about writable. You can very comfortably just test for readable events using Select() before calling Receive.
You didn't indicate the type of client
but you mentioned UDP so I assume you're using the System.Net.Socket.UDPClient class. If so, that's perfect and will work with Socket.Select().
Hope that helps.
-Warwick
@Wazza$$anonymous$$ Thank you for such an indepth answer :). I followed your advice and the link you sent to make this:
byte[] data = Encoding.UTF8.GetBytes(message);
client.Send(data, data.Length, remoteEndPoint);
//PREPARING TO RECEIVE
byte[] recv = new byte[1024];
String result = "false";
Socket socket1 = new Socket(AddressFamily.InterNetwork , SocketType.Dgram , ProtocolType.Udp);
IPEndPoint ep = new IPEndPoint (IPAddress.Any, port);
socket1.Bind(ep);
socket1.Listen(10);
List<Socket> sList = new List<Socket>();
sList.Add(socket1);
Socket.Select(sList , null , null , 1000);
socket1.Accept();
socket1.Receive(recv);
result = System.Text.Encoding.UTF8.GetString(recv);
socket1.Close();
But now it shows an error for line socket1.Bind(...) :
SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.
System.Net.Sockets.Socket.Bind (System.Net.EndPoint local_end)
UDPSend.sendString (System.String message) (at Assets/$$anonymous$$y Scripts/UDPSend.cs:273)
UDPSend.GetStatus () (at Assets/$$anonymous$$y Scripts/UDPSend.cs:166)
And for the line socket1.Listen(..) it shows this:
SocketException: The attempted operation is not supported for the type of object referenced.
System.Net.Sockets.Socket.Listen (Int32 backlog)
UDPSend.sendString (System.String message) (at Assets/$$anonymous$$y Scripts/UDPSend.cs:274)
UDPSend.GetStatus () (at Assets/$$anonymous$$y Scripts/UDPSend.cs:166)
Do you know what is causing this issue? Thanks, Regards
Answer by meat5000 · Apr 01, 2018 at 02:32 PM
Perhaps you can use this :
https://docs.unity3d.com/ScriptReference/Network.OnDisconnectedFromServer.html
To disable your Receiver.
I'd try to make a class variable bool canReceive
and make it false in the OnDisconnectedFromServer callback. Then simply wrap your receive statement with it
if(canReceive)
{
byte[] recv = client.Receive(ref remoteEndPoint);
}
This should hopefully skip the freeze on disconnect.
@meat5000 thanks for the answer. Would this work with UDP connections?
I presume so. Doesn't Unity networking only do UDP? :) The other thing you can do is add a TimeOut to the receiver.
The OnDisconnectefFromServer message is a while other thing, relying on unity networking.
Take a look at unity blogs about UNET add it was called during the day. Yes, it's based on UDP but it implements messages and connections through protocols unity developed on top of UDP. See https://blogs.unity3d.com/2014/06/11/all-about-the-unity-networking-transport-layer/
Anyway, straight UDP can be very powerful and simple if you follow a peer to peer pattern.
I wrote an article about this one in unity connect to address all this, about using sockets and where TCP is good versus where UDP I'd good.