Search Unity

.NET Sockets + web player + reload = crash

Discussion in 'Multiplayer' started by gunder, Jun 23, 2009.

  1. gunder

    gunder

    Joined:
    Jun 23, 2009
    Posts:
    16
    Hi folks,

    i have a class to create a socket asyn communication with a server. Using editor its works fine. Using standalone version works great. Using web player works like silk. But once i connect the client with the server, i reload the web page ( not close it, only reload ) my game crash.

    Anyone can help me???

    Thanks in advance.
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Do you shutdown the socket when ending the player (reloading ends the player and restarts it too)
     
  3. gunder

    gunder

    Joined:
    Jun 23, 2009
    Posts:
    16
    Yes i do it,

    Here is the code...

    Code (csharp):
    1.  
    2. using System;
    3. using System.Net.Sockets;
    4. using UnityEngine;
    5.  
    6. public class Connector: MonoBehaviour {
    7.     const int BUFFER_SIZE = 2048;
    8.     private byte[] readBuffer = new byte[BUFFER_SIZE];
    9.     private Socket client=null;
    10.  
    11.     void Start(){
    12.         try{
    13.             // Create socket and start async connection on locahost:50001
    14.             client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
    15.             client.BeginConnect("localhost", 50001, new AsyncCallback(onConnect), null );
    16.         }catch(Exception) {
    17.             Debug.Log("Error on Connector.connect." );
    18.         }
    19.     }
    20.    
    21.     void OnApplicationQuit(){
    22.         client.Shutdown(SocketShutdown.Both);
    23.         client.Close();
    24.     }
    25.    
    26.    
    27.     private void onConnect(IAsyncResult ar){
    28.         try{
    29.             // Connection success, start async read.
    30.             client.EndConnect(ar);
    31.             client.BeginReceive ( readBuffer, 0, BUFFER_SIZE, SocketFlags.None, new AsyncCallback(onReceive), null);
    32.         }
    33.         catch (Exception){
    34.             Debug.Log("Error on Connector.onConnect." );
    35.         }
    36.     }
    37.    
    38.     private void onReceive(IAsyncResult ar){
    39.         try{
    40.         // Read sucess, and once time again.
    41.         int len = client.EndReceive(ar);
    42.             Debug.Log("Connector.onReceive "+len);
    43.             client.BeginReceive ( readBuffer, 0, BUFFER_SIZE, SocketFlags.None, new AsyncCallback(onReceive), null);
    44.         }
    45.         catch (Exception){
    46.             Debug.Log("Error on Connector.onReceive." );
    47.         }
    48.     }
    49.    
    50.     public void Send(  byte[] buffer, int len ){
    51.         client.Send( buffer,  len, SocketFlags.None);
    52.     }
    53.  
    54. }
    55.  
     
  4. perlohmann

    perlohmann

    Joined:
    Feb 12, 2009
    Posts:
    221
    well one thing comes to mind.

    In your onReceive function check for the length being = 0 before doing another async receive.

    when using tcp a length of 0 and a call to the receive callback means the socket is closing down.

    so:

    Code (csharp):
    1.  
    2. private void onReceive(IAsyncResult ar)
    3. {
    4.    try
    5.    {
    6.       // Read sucess, and once time again.
    7.       int len = client.EndReceive(ar);
    8.       if (len > 0)
    9.       {
    10.          Debug.Log("Connector.onReceive "+len);
    11.          client.BeginReceive ( readBuffer, 0, BUFFER_SIZE, SocketFlags.None, new AsyncCallback(onReceive), null);
    12.       }
    13.    }
    14.    catch (Exception)
    15.    {
    16.       Debug.Log("Error on Connector.onReceive." );
    17.    }
    18. }
    19.  
    //perlohmann
     
  5. gunder

    gunder

    Joined:
    Jun 23, 2009
    Posts:
    16
    Hi perlohmann,

    you are in rigth. But unfortunately that is not the problem, app still crashing.

    Thanks for the try.
     
  6. perlohmann

    perlohmann

    Joined:
    Feb 12, 2009
    Posts:
    221
    another thing could be that you use the socket as a member var.

    you should pass the socket as part of the AsyncCallback's last parameter. And in the callback function retreive it through the IAsyncResult.

    But I kinda doubt its that.

    you could try and totally remove the ability to "receive" in the class to check out if it is the onReceive that is making the trouble (my 262nd sense tell me it is).

    that way you are sure the setting up and tearing down of connections isnt the issue.

    //perlohmann
     
  7. gunder

    gunder

    Joined:
    Jun 23, 2009
    Posts:
    16
    Severals tries after, i think the porblem is in the async functions ( beginconnect and beginrecive). I'll decide to chage al to non asyc.

    Code (csharp):
    1.  
    2. using System;
    3. using System.Net.Sockets;
    4. using UnityEngine;
    5.  
    6. public class Connector: MonoBehaviour {
    7.     const int BUFFER_SIZE = 2048;
    8.     private byte[] readBuffer = new byte[BUFFER_SIZE];
    9.     private static Socket client=null;
    10.  
    11.    void Start(){
    12.       try{
    13.         // Create socket and start async connection on locahost:50001
    14.         client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
    15.         client.Blocking=false;
    16.         client.Connect("localhost", 50001);
    17.       }catch(Exception) {
    18.          Debug.Log("Error on Connector.connect." );
    19.       }
    20.    }
    21.    
    22.    void Update(){
    23.        if( client.Connected  client.Available!=0 ){
    24.             Debug.Log("Connector.onReceive "+client.Available);
    25.             client.Receive( readBuffer, BUFFER_SIZE, SocketFlags.None );
    26.        }       
    27.    }
    28.    
    29.    void OnApplicationQuit(){
    30.       client.Shutdown(SocketShutdown.Both);
    31.       client.Close();
    32.    }
    33.    
    34.    public void Send(  byte[] buffer, int len ){
    35.       client.Send( buffer,  len, SocketFlags.None);
    36.    }
    37. }
    38.  

    Thanks a lot.
     
  8. protozerg

    protozerg

    Joined:
    Apr 28, 2009
    Posts:
    23
    hi,

    Have you had any problem yet after changing to

    non-async functions?

    I have a similar problem, crashing, like yours.

    I made a networking DLL with C# form VS2008 with

    using Async functions (BeginReceive, BeginSend).

    My game has been crashed suddenly for both editor

    mode and standalone mode.

    Does Unity not support Async functions?
     
  9. magwo

    magwo

    Joined:
    May 20, 2009
    Posts:
    402
    Are you sure this was not caused by your calls to Debug.Log() and similar Unity functions? These callbacks are running in in other threads if I'm not mistaken.
     
  10. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    This thread is very old :)
    The async socket was reworked.
     
  11. madmat

    madmat

    Joined:
    Mar 4, 2010
    Posts:
    6
    Hi Dreamora,

    I've installed the latest version of Unity (2.6) but I'm experiencing the same issue than described above.
    Surprisingly, everything works fine with a stand-alone application, but the same code executed with the web player makes it crash when I reload the page.
    Do you know if the async socket was somehow reworked with the standalone client, but not with the web player?

    Thanks a lot in advance.
     
  12. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    in the webplayer the player is fully controlled by the website. a reload for example means shutdown - restart and alike
    So usage of onapplicationquit and try-catch is a MUST because if you try to use a socket thats still allocated and don't handle it appropriately you will bomb it

    also the networking on various parts is the one of the browser (WWW for example) and the webplayer only runs within a single thread likely (as any plugin)
     
  13. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    It crashes because the socket is still in open state and you are trying to open an already opened socket, just because the browser isn't smart enough to know this doesn't mean much, also another thing to note, onApplicationQuit doesn't really do squat for a browser page because there is no way for Unity to really know if the application is propertly terminating in a web browser and handle your socket.

    Wrap a try catch around the clientShutdown and client Close in the OnApplicationQuit, other than that, I still think in a web browser it is going to blow up.
     
  14. TrickyFishy

    TrickyFishy

    Joined:
    Aug 27, 2009
    Posts:
    39
    Plugins hosted by a browser are running in single threaded apartments but the plugin itself can spawn all the threads it likes. Calls made into and out of the plugin must be marshalled on to the same thread that the plugin was created on.

    I made an example for you to look at:
    http://www.bakedon.com/2010/03/untiy3d-asynchronous-sockets/
     
  15. tigeba

    tigeba

    Joined:
    Sep 11, 2008
    Posts:
    70
    It only took one start and stop for your example project to crash the editor ( 2.6.1, OSX). Despite using what should be proper thread-isolation, my experience is that the only way to avoid these is to not use the async sockets. It is my assertion that this is probably related to the older version of Mono that Unity uses. I suppose I could try it out in the new version of Unity iPhone and see :)
     
  16. tbryant

    tbryant

    Joined:
    Aug 12, 2009
    Posts:
    17
    I'm seeing similar behavior (crashes in editor with beginreceive) in 2.6.1 OSX as well. I'm wondering if someone can confirm tigeba's assertion about the older mono?

    Will this change in Unity 3?
     
  17. CHP

    CHP

    Joined:
    Mar 30, 2010
    Posts:
    2
    There is already a mono-bugs ticket for this issue: http://www.mail-archive.com/mono-bugs@lists.ximian.com/msg70822.html

    I can reproduce this bug without using async socket io. Basically I have a thread started whith ThreadPool.QueueUserWorkItem. In this thread I use synchronous Socket.Send and Socket.Recieve. In OnApplicationQuit() I end my thread and close the socket, but even my UnityEditor crashes, if I close it less than one second after stopping the game.

    Next thing I tried is to disable all socket io, and it still crashes. So basically the bug is not directly dependand on sockets, but rather on threads.
     
  18. attiksystem

    attiksystem

    Joined:
    Aug 21, 2012
    Posts:
    23
    Hi, two years later, with Unity 4.0, I still have problems with Async Sockets in a Webplayer: the first time I load the web page contanining the web player, everything is fine, but after a reload, I cannot receive anything anymore. I'm not using threads at all, and I have the feeling I'm doing socket cleanup correctly.

    Here is the code, in case it can help:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. using System;
    5.  
    6. public class EchoTest : MonoBehaviour {
    7.     // The sockets
    8.     private AsynchronousSocket asocket;
    9.     private AsynchronousSocket asocket2;
    10.  
    11.     void Start() {
    12.         try {
    13.            
    14.             asocket = ScriptableObject.CreateInstance<AsynchronousSocket>();
    15.             asocket2 = ScriptableObject.CreateInstance<AsynchronousSocket>();
    16.            
    17.             // Connect to the remote endpoint.
    18.             asocket.ConnectSynchronously("www.attiksystem.ch", 7);
    19.             asocket2.ConnectSynchronously("www.attiksystem.ch", 7);
    20.            
    21.             // Wait if connect asynchronously
    22.             //System.Threading.Thread.Sleep(1000);
    23.  
    24.             // Setup receive socket callback
    25.             asocket.Receive();
    26.             asocket2.Receive();
    27.            
    28.             // Send data
    29.             asocket.Send("Hello Unity");
    30.             asocket2.Send("Hello Async Socket");
    31.             asocket2.Send("Hello Async Socket");
    32.             asocket.Send("Hello Unity");
    33.             asocket.Send("Hello Unity");
    34.             asocket.Send("Hello Unity");
    35.             asocket.Send("Hello Unity");
    36.             asocket.Send("Hello Unity");
    37.             asocket.Send("Hello Unity");
    38.             System.Threading.Thread.Sleep(1000);
    39.             asocket.Send("Hello Unity");
    40.             asocket.Send("Hello Unity");
    41.             asocket.Send("Hello Unity");
    42.             asocket.Send("Hello Unity");
    43.             asocket2.Send("Hello Async Socket");
    44.             asocket.Send("Hello Unity");
    45.            
    46.         } catch (Exception e) {
    47.             Debug.Log(e.ToString());
    48.         }
    49.     }
    50.    
    51.     void OnApplicationQuit()
    52.     {
    53.         asocket.Disconnect();
    54.         asocket2.Disconnect();
    55.     }
    56. }
    Code (csharp):
    1. using UnityEngine;
    2.  
    3. using System;
    4. using System.Net;
    5. using System.Net.Sockets;
    6. using System.Text;
    7.  
    8. // State object for receiving data from remote device.
    9. public class StateObject {
    10.     public const int BufferSize = 1024;             // Size of receive buffer.
    11.     public byte[] buffer = new byte[BufferSize];    // Receive buffer.
    12. }
    13.  
    14. // Async socket
    15. public class AsynchronousSocket : ScriptableObject {
    16.    
    17.     private Socket client;
    18.    
    19.     public void ConnectSynchronously(string host, int port) {
    20.         try {
    21.             // Establish the remote endpoint for the socket.
    22.             IPHostEntry ipHostInfo = Dns.GetHostEntry(host);
    23.             IPAddress ipAddress = ipHostInfo.AddressList[0];
    24.             IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
    25.  
    26.             // Create a TCP/IP socket.
    27.             client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    28.            
    29.             client.Connect(remoteEP);
    30.         } catch (Exception e) {
    31.             Debug.Log(e.ToString());
    32.         }
    33.     }
    34.    
    35.     public void Connect(string host, int port) {
    36.         try {
    37.             // Establish the remote endpoint for the socket.
    38.             IPHostEntry ipHostInfo = Dns.GetHostEntry(host);
    39.             IPAddress ipAddress = ipHostInfo.AddressList[0];
    40.             IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
    41.  
    42.             // Create a TCP/IP socket.
    43.             client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    44.            
    45.             client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
    46.         } catch (Exception e) {
    47.             Debug.Log(e.ToString());
    48.         }
    49.     }
    50.  
    51.     private void ConnectCallback(IAsyncResult ar) {
    52.         try {
    53.             // Complete the connection.
    54.             client.EndConnect(ar);
    55.  
    56.             Debug.Log("Socket connected to " + client.RemoteEndPoint.ToString());
    57.         } catch (Exception e) {
    58.             Debug.Log(e.ToString());
    59.         }
    60.     }
    61.    
    62.     public void Disconnect() {
    63.         // Release the socket.
    64.         Debug.Log("Releasing socket");
    65.         client.Shutdown(SocketShutdown.Both);
    66.         client.Close();
    67.     }
    68.  
    69.     public void Receive() {
    70.         try {
    71.             // Create the state object.
    72.             StateObject state = new StateObject();
    73.  
    74.             // Begin receiving the data from the remote device.
    75.             client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
    76.         } catch (Exception e) {
    77.             Debug.Log(e.ToString());
    78.         }
    79.     }
    80.  
    81.     private void ReceiveCallback( IAsyncResult ar ) {
    82.         try {
    83.             // Retrieve the state object and the client socket
    84.             // from the asynchronous state object.
    85.             StateObject state = (StateObject) ar.AsyncState;
    86.  
    87.             // Read data from the remote device.
    88.             int bytesRead = client.EndReceive(ar);
    89.             Debug.Log("Received " + bytesRead + " bytes from server.");
    90.  
    91.             if (bytesRead > 0) {
    92.  
    93.                 // There might be more data, so store the data received so far.
    94.                 Debug.Log("Received data = " + Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
    95.  
    96.                 // Get the rest of the data.
    97.                 client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
    98.             }
    99.         } catch (Exception e) {
    100.             Debug.Log(e.ToString());
    101.         }
    102.     }
    103.  
    104.     public void Send(String data) {
    105.         // Convert the string data to byte data using ASCII encoding.
    106.         byte[] byteData = Encoding.ASCII.GetBytes(data);
    107.  
    108.         // Begin sending the data to the remote device.
    109.         client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
    110.     }
    111.  
    112.     private void SendCallback(IAsyncResult ar) {
    113.         try {
    114.             // Complete sending the data to the remote device.
    115.             int bytesSent = client.EndSend(ar);
    116.            
    117.             Debug.Log("Sent " + bytesSent + " bytes to server.");
    118.         } catch (Exception e) {
    119.             Debug.Log(e.ToString());
    120.         }
    121.     }
    122. }
    The first time I run the webplayer app, here is what I can read in the log:

    But after a reload:

    Are asynchronous sockets really stable in a webplayer?
     
    Last edited: Nov 15, 2012
  19. disturbing

    disturbing

    Joined:
    Dec 12, 2010
    Posts:
    127
    Hey

    I'm receiving the same problem. The connection is successful, but then receives 0 bytes from server.

    This is definitely an issue with web player on Mac + OSX only. Any ideas on a fix?

    Best Regards,

    Joseph Cooper