properly disconnect local client without freezing by limiting unread message queue length and properly disconnecting when the socket dies

upm
Anton Franzluebbers 2022-03-10 20:08:29 -05:00
parent bca55cccbc
commit 36f16b35df
2 changed files with 60 additions and 19 deletions

View File

@ -211,6 +211,7 @@ namespace VelNet
{ {
} }
private int maxUnreadMessages = 1000;
public readonly List<Message> receivedMessages = new List<Message>(); public readonly List<Message> receivedMessages = new List<Message>();
private void Awake() private void Awake()
@ -227,21 +228,26 @@ namespace VelNet
// add all local network objects // add all local network objects
sceneObjects = FindObjectsOfType<NetworkObject>().Where(o => o.isSceneObject).ToArray(); sceneObjects = FindObjectsOfType<NetworkObject>().Where(o => o.isSceneObject).ToArray();
}; };
ConnectToServer(); ConnectToServer();
} }
private void AddMessage(Message m) private void AddMessage(Message m)
{ {
bool added = false;
lock (receivedMessages) lock (receivedMessages)
{ {
//Debug.Log(messagesReceived++); // this is to avoid backups when headset goes to sleep
receivedMessages.Add(m); if (receivedMessages.Count < maxUnreadMessages)
{
receivedMessages.Add(m);
added = true;
}
} }
try try
{ {
MessageReceived?.Invoke(m); if (added) MessageReceived?.Invoke(m);
} }
catch (Exception e) catch (Exception e)
{ {
@ -279,6 +285,7 @@ namespace VelNet
Debug.Log("Received duplicate login message " + userid); Debug.Log("Received duplicate login message " + userid);
return; return;
} }
userid = lm.userId; userid = lm.userId;
Debug.Log("Joined server " + userid); Debug.Log("Joined server " + userid);
@ -529,6 +536,7 @@ namespace VelNet
private void LeaveRoom() private void LeaveRoom()
{ {
Debug.Log("Leaving Room");
string oldRoom = LocalPlayer?.room; string oldRoom = LocalPlayer?.room;
// delete all NetworkObjects that aren't scene objects or are null now // delete all NetworkObjects that aren't scene objects or are null now
objects objects
@ -556,12 +564,12 @@ namespace VelNet
{ {
Debug.LogError(e); Debug.LogError(e);
} }
foreach (NetworkObject s in sceneObjects) foreach (NetworkObject s in sceneObjects)
{ {
s.owner = null; s.owner = null;
} }
players.Clear(); players.Clear();
masterPlayer = null; masterPlayer = null;
} }
@ -591,12 +599,37 @@ namespace VelNet
private void DisconnectFromServer() private void DisconnectFromServer()
{ {
LeaveRoom(); Debug.Log("Disconnecting from server");
Debug.Log("Leaving Room");
string oldRoom = LocalPlayer?.room;
// delete all NetworkObjects that aren't scene objects or are null now
objects
.Where(kvp => kvp.Value == null || !kvp.Value.isSceneObject)
.Select(o => o.Key)
.ToList().ForEach(SomebodyDestroyedNetworkObject);
// then remove references to the ones that are left
objects.Clear();
instance.groups.Clear();
foreach (NetworkObject s in sceneObjects)
{
s.owner = null;
}
players.Clear();
masterPlayer = null;
connected = false; connected = false;
udpConnected = false; udpConnected = false;
socketConnection?.Close(); socketConnection?.Close();
clientReceiveThreadUDP?.Abort(); clientReceiveThreadUDP?.Abort();
clientReceiveThread?.Abort(); clientReceiveThread?.Abort();
clientReceiveThread = null;
socketConnection = null; socketConnection = null;
udpSocket = null; udpSocket = null;
} }
@ -637,7 +670,7 @@ namespace VelNet
using BinaryReader reader = new BinaryReader(stream); using BinaryReader reader = new BinaryReader(stream);
//now we are connected, so add a message to the queue //now we are connected, so add a message to the queue
AddMessage(new ConnectedMessage()); AddMessage(new ConnectedMessage());
while (true) while (socketConnection.Connected)
{ {
//read a byte //read a byte
MessageReceivedType type = (MessageReceivedType)stream.ReadByte(); MessageReceivedType type = (MessageReceivedType)stream.ReadByte();
@ -856,15 +889,16 @@ namespace VelNet
/// <summary> /// <summary>
/// Send message to server using socket connection. /// Send message to server using socket connection.
/// </summary>
/// <param name="message">We can assume that this message is already formatted, so we just send it</param> /// <param name="message">We can assume that this message is already formatted, so we just send it</param>
/// </summary> /// <returns>True if the message successfully sent. False if it failed and we should quit</returns>
private static void SendTcpMessage(byte[] message) private static bool SendTcpMessage(byte[] message)
{ {
// Debug.Log("Sent: " + clientMessage); // Debug.Log("Sent: " + clientMessage);
if (instance.socketConnection == null) if (instance.socketConnection == null)
{ {
Debug.LogError("Tried to send message while socket connection was still null.", instance); Debug.LogError("Tried to send message while socket connection was still null.", instance);
return; return false;
} }
try try
@ -874,9 +908,9 @@ namespace VelNet
{ {
instance.DisconnectFromServer(); instance.DisconnectFromServer();
Debug.LogError("Disconnected from server. Most likely due to timeout."); Debug.LogError("Disconnected from server. Most likely due to timeout.");
return; return false;
} }
// Get a stream object for writing. // Get a stream object for writing.
NetworkStream stream = instance.socketConnection.GetStream(); NetworkStream stream = instance.socketConnection.GetStream();
if (stream.CanWrite) if (stream.CanWrite)
@ -884,10 +918,18 @@ namespace VelNet
stream.Write(message, 0, message.Length); stream.Write(message, 0, message.Length);
} }
} }
catch (IOException ioException)
{
instance.DisconnectFromServer();
Debug.LogError("Disconnected from server. Most likely due to timeout.\n" + ioException);
return false;
}
catch (SocketException socketException) catch (SocketException socketException)
{ {
Debug.Log("Socket exception: " + socketException); Debug.Log("Socket exception: " + socketException);
} }
return true;
} }
private static byte[] get_be_bytes(int n) private static byte[] get_be_bytes(int n)
@ -1132,7 +1174,7 @@ namespace VelNet
{ {
if (!instance.objects.ContainsKey(networkId)) return; if (!instance.objects.ContainsKey(networkId)) return;
NetworkObject obj = instance.objects[networkId]; NetworkObject obj = instance.objects[networkId];
// clean up if this is null // clean up if this is null
if (obj == null) if (obj == null)
{ {
@ -1140,7 +1182,7 @@ namespace VelNet
Debug.LogError("Object to delete was already null"); Debug.LogError("Object to delete was already null");
return; return;
} }
// Delete locally immediately // Delete locally immediately
SomebodyDestroyedNetworkObject(networkId); SomebodyDestroyedNetworkObject(networkId);
@ -1150,10 +1192,9 @@ namespace VelNet
writer.Write((byte)MessageType.Destroy); writer.Write((byte)MessageType.Destroy);
writer.Write(networkId); writer.Write(networkId);
SendToRoom(mem.ToArray(), include_self: false, reliable: true); SendToRoom(mem.ToArray(), include_self: false, reliable: true);
} }
public static void SomebodyDestroyedNetworkObject(string networkId) public static void SomebodyDestroyedNetworkObject(string networkId)
{ {
if (!instance.objects.ContainsKey(networkId)) return; if (!instance.objects.ContainsKey(networkId)) return;

View File

@ -1,7 +1,7 @@
{ {
"name": "edu.uga.engr.vel.velnet", "name": "edu.uga.engr.vel.velnet",
"displayName": "VelNet", "displayName": "VelNet",
"version": "1.0.11", "version": "1.0.12",
"unity": "2019.1", "unity": "2019.1",
"description": "A custom networking library for Unity.", "description": "A custom networking library for Unity.",
"keywords": [ "keywords": [