Webplayer reload fubars socket on reload

Hi - I am desperately trying to get this one working, so time to turn to the forums, and hopefully Aras or someone similar knows the answer.

I am putting the finihing touches on the SmartFoxServer API, and that uses TcpClient/Sockets for communicating with a backend server over TCP.

This works great until you hit reload in the browser.

After that it is impossible to use the sockets. Trying to connect gives this exception:

System.Net.Sockets.SocketException: No route to host
  at System.Net.Sockets.Socket.Connect (System.Net.EndPoint remote_end) [0x00000] 
  at System.Net.Sockets.TcpClient.Connect (System.Net.IPEndPoint remote_end_point) [0x00000] 
  at System.Net.Sockets.TcpClient.Connect (System.Net.IPAddress[] ipAddresses, Int32 port) [0x00000]

Notice that this worked 2 seconds before and that I am trying to connect to localhost and/or 127.0.0.1 as hostname.

I have been trying all sorts of disconnect and iDispose variations to see if it could be a matter of improper shutdown - but to no help.

My stummach starts to tell me that this could be a mono or Unity issue, but I really am guessing blindly at this point.

This is one of the very last issues I have, and I am hitting a brick wall. If anyone can give me a clue, then you will be my hero of the day :smiley:

Thanks!

/Thomas

I tried to make a minimal testscript and wanted to post it here for comments before filing a bugreport.

Would be weird if I was the first to hit this bug, so I am not ruling out me as the bugsource.

Beware that the code crashes firefox with a null pointer. Run this in Safari please to see the bug

To reproduce simply load this in the webplayer, press connect and see the HTML ouytput (a 302 moved message).

Hit reload, wait until Unity launches and hit the connect button again.

This produces (with this test case) a “No such host is known” socket exception.

using UnityEngine;
using System;
using System.Net;
using System.IO;
using System.Net.Sockets;
using System.Text;

public class TestCaseScript : MonoBehaviour
{
	string serverName = "unity3d.com";
	int serverPort = 80;
	
	string downloadMessage = "";
	
	void OnGUI()
	{
		GUI.Label(new Rect(10, 30, 500, 100), "Server Name: ");
		serverName = GUI.TextField(new Rect(100, 30, 200, 20), serverName, 25);

		GUI.Label(new Rect(10, 50, 500, 100), "Server Port: ");
		string tmpPortString = GUI.TextField(new Rect(100, 50, 200, 20), serverPort.ToString(), 4);
		int tmpPort;
		if (int.TryParse(tmpPortString, out tmpPort))
			serverPort = tmpPort;

		if (GUI.Button(new Rect(100, 80, 80, 30), "Connect"))
		{
            TcpClient client = null;

            try
            {
                client = new TcpClient(serverName, serverPort);

                StringBuilder sb = new System.Text.StringBuilder();
                sb.Append("GET / HTTP/1.0\r\n");
                sb.Append("\r\n");

                StreamWriter writer = new StreamWriter(client.GetStream());
                writer.Write(sb.ToString() + (char)0);
                writer.Flush();
                
                System.Text.StringBuilder responseFromServer = new System.Text.StringBuilder();
                int ct = 0;
                byte[] receive = new byte[4096];
                while ((ct = client.GetStream().Read(receive, 0, 4096)) > 0)
                {
                    // Add the received byte message to the messageBuffer, so we can cut up that one                 
                    responseFromServer.Append(Encoding.UTF8.GetString(receive));
                    receive = new byte[4096];
                }

                Debug.Log("Response: " + responseFromServer.ToString());
                downloadMessage = responseFromServer.ToString();

            }
            catch (Exception e)
            {
				downloadMessage = e.ToString();
            }
            finally
            {
                try
                {
                    client.Close();
                }
                catch (System.NullReferenceException e) { 
                	Debug.Log("Http error trying to close connection on null object: " + e.ToString());
                }
            }
		}

		GUI.Label(new Rect(10, 140, 500, 100), downloadMessage);
	}
}

To clarify though, all of this is working fine in a standalone player?

Hi Charles!

Thanks for the question. Yes - the code works fine in the stand alone player.

It also works in the webplayer if I do “disconnects” and “connects” via buttons.

The problem comes when the webplayer gets reloaded in a browser as long as that browser was not shut down.

So hitting reload is one scenario - or having the game in a tab, closing the tab and later opening that URL again.

This has been tested on OSX with latest Unity. Have had no chance to test on Windows.

/Thomas

Oh - and to answer a potential “workaround” advice up front.

I cannot use the WWW class for this or other Unity only socket wrappers, as the code is a standard .NET dll. The above is simply a test case to minimalistic show the issue.

:slight_smile:

Always great to be able to answer your own issues.

http://forum.unity3d.com/viewtopic.php?t=13483

Not so great that the bug exists, but I (and everyone else) will have to live with this until Unity decides to upgrade mono to a non-buggy version.

Does OnApplicationQuit get called when doing a browser refresh? What happens when you just put the disconnect in there?

Hey Proton

I’ve tried everything (at least thats how it feels). And nothing to do about it except enforce ip addresses.

That “fixes” (= work around) the issue for now

Hi Thomas Lund,

I do Shutdown and Close Socket in OnApplicationQuit.

But my firefox always is crashed when I closed it. Have any tip fix this?

Thanks!

The debugging scenario that I’ve found “most productive” if one can say that is to run the code in safari and watch what exception is thrown through the player.log

Firefox crashes on any uncaught exception, so a FF crash can turn out to be anything really.

Check what the exception is - typically NPE - and then start inserting debug statememts in your code and comment out large blocks until it works - then work backward from there.

Thank for reply!

  • When I run that script on MacOS(Firefox, Safari), it is normal, mean NO crash when I close tab.

  • When I run on Windows OS (FireFox, Safari) then crash will occur. But IE run well. I see: when I close tab of FireFox or Safari, OnApplicationQuit() is called immediately. But when I close IE Tabs, seem OnApplicationQuit() is not called, it is called when I closed IE browser.

  • And I don’t know how to debug on Windows OS using Firefox or Safari.

Could you please help me this!

Sorry - I am at a loss on how the webplayer works on Windows.

In general you can try to use iDispose for cleaning up unmanaged resources like sockets instead of using onApplicationQuit. If that will fix it for you - dont know!

Thank Thomas!

I have already fixed it.
The crash occurs when i use asynchronous socket: BeginConnect and BeginReceive methods. Now, I switch to use Thread.

Ah yes - cant remember if I posted that here or in another thread.

But in general - everything that internally in mono uses threads are not properly cleaned up. So do it yourself.

Meaning - if you need a timer, then dont use the System Timers - they use threads internally. Set up your own thread with a timed callback etc.etc. Async calls (including WebRequest) uses internal threads too.