C# Socket Issues

  1. If I open a .NET socket in C# and don’t connect to it before hitting the STOP button in the editor the socket binding is not removed. This prevents the app from binding the next time I hit PLAY.

  2. If I am accessing the C# server script to send some data from a JavaScript is it possible to recompile the JS without fubaring Mono? Right now if I modify the JS the C# class seems to recompile (or something is moved in memory?) causing null exceptions within the C# script. The script is a modified version of the NetworkCursor server script on the Wiki.

  3. The Mono impl. used doesn’t seem to properly detect a socket that was closed from the remote machine. The isConnected() function (taken from the MSDN docs) as well as socket.Connected always return true after closing the connection.

Note I’ve done all the testing so far using Telnet to connect to the socket.

using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.Net;
using System.Text;
 
public class Server : MonoBehaviour {
	public int port = 9349;
    static Server theServer;
    
    private Socket m_Socket;
    
    ArrayList m_Connections = new ArrayList ();
    
    ArrayList m_rBuffer = new ArrayList ();
	ArrayList m_sBuffer = new ArrayList ();
    ArrayList m_ByteBuffer = new ArrayList ();
    
    void Awake ()
    {
        m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);     
        IPEndPoint ipLocal = new IPEndPoint ( IPAddress.Any , port);
 
        m_Socket.Bind( ipLocal );
    
        //start listening...
        m_Socket.Listen (100);
        theServer = this;

//		Debug.Log("Listening on: " + ((IPEndPoint)m_Socket.LocalEndPoint).Address + ":" + ((IPEndPoint)m_Socket.LocalEndPoint).Port);

    }
    
    void OnApplicationQuit ()
    {
        Cleanup();
    }
    
    void Cleanup ()
    {
        if (m_Socket != null)
            m_Socket.Close();
        m_Socket = null;
    
        foreach (Socket con in m_Connections)
            con.Close();
        m_Connections.Clear();
    }   
    ~Server ()
    {
        Cleanup();      
    }
    
    void LateUpdate ()
    {
        // Accept any incoming connections!
        ArrayList listenList = new ArrayList();
        listenList.Add(m_Socket);
        Socket.Select(listenList, null, null, 1000);
        for( int i = 0; i < listenList.Count; i++ )
        {
            Socket newSocket = ((Socket)listenList[i]).Accept();
            m_Connections.Add(newSocket);
            m_ByteBuffer.Add(new ArrayList());
            Debug.Log("Did connect");
        }
        
        if (m_Connections.Count != 0){
			ArrayList connections = new ArrayList (m_Connections);
			//Remove closed sockets from the list
			foreach (Socket socket in connections){
				if(isConnected(socket)==false){
					socket.Close();
					theServer.m_ByteBuffer.RemoveAt(m_Connections.IndexOf(socket));
					theServer.m_Connections.Remove(socket); 
				}
			}
		}
		
		

        // Read  Write data from the connections!
        if (m_Connections.Count != 0)
        {
			// Write data to connections
			ArrayList connections = new ArrayList (m_Connections);
            Socket.Select(null, connections, null, 1000);

			while (theServer.m_sBuffer.Count>0){
				byte[] sndBytes = new byte[((string)theServer.m_sBuffer[0]).Length];
				string theString = (string)theServer.m_sBuffer[0];
				for(int i=0;i<sndBytes.Length;i++){
					sndBytes[i]=(byte)theString[i];
				}
				foreach(Socket socket in connections){
					if(socket.Connected==false)break; 			
					socket.Send(sndBytes);		
				}			
				theServer.m_sBuffer.RemoveAt(0);
			}

			connections = new ArrayList (m_Connections);
            Socket.Select(connections, null, null, 1000);
            // Go through all sockets that have data incoming!
            foreach (Socket socket in connections)
            {	

				if(socket.Connected==true){
				byte[] receivedbytes = new byte[512];
                
				ArrayList buffer = (ArrayList)m_ByteBuffer[m_Connections.IndexOf(socket)];
                int read = socket.Receive(receivedbytes);
				
                if(receivedbytes[0]!=0) {
					for (int i=0;i<read;i++) buffer.Add(receivedbytes[i]);
				}


				while (buffer.Count > 0)
                {

                        ArrayList thismsgBytes = new ArrayList(buffer);
						int length=thismsgBytes.Count;

                        if (thismsgBytes.Count != length) Debug.Log("Bug");
                        
                        buffer.RemoveRange(0, length);
                        byte[] readbytes = (byte[])thismsgBytes.ToArray(typeof(byte));

						string readString = "";
						foreach(byte b in readbytes){
							readString+=(char)b;
						}
						
// 						Debug.Log(readString);

                        theServer.m_rBuffer.Add(readString);
                        
                        if (theServer != this)
                            Debug.Log("Bug");   
                    }
            	}
			}           
        }
    }

	//Get a message from the received queue
    static public string GetMessage ()
    {
        if(theServer!=null){	
			if (theServer.m_rBuffer.Count == 0)
        	{
        	    return null;
        	}
        	else
        	{
        	    string readMsg = (string)theServer.m_rBuffer[0];
        	    theServer.m_rBuffer.RemoveAt(0);
        	    return readMsg;
        	}
		}
		else return null;
    }

	//Put a message in the outgoing queue
	static public int PutMessage(string sendMsg){
		if(theServer!=null){
			if(theServer.m_sBuffer.Count>1000) theServer.m_sBuffer.Clear(); //if there is a backlog of more than 1000 messages clear the queue
			return theServer.m_sBuffer.Add(sendMsg);
		}
		else return -1;
	}
	
	//Convert a string to a byte array
	static ArrayList StringToBytes(string theString){
		ArrayList bytes=new ArrayList();
		foreach(char c in theString.ToCharArray()){
			bytes.Add((byte)c);
		}
		return bytes;
	}
	
	//Returns true if there are messages waiting to be read in the received queue
	static public int MessageAvailable(){
		if(theServer!=null) return theServer.m_rBuffer.Count;
		else return -1;
	}
	
	//Returns true if there are connections in the connection list
	static public bool Connected(){
		if(theServer!=null  theServer.m_Connections.Count>0) return true;
		else return false;
	}
	
	//Number of messages waiting to be sent
	static public int SendBufferBackLog(){
		if(theServer!=null)return theServer.m_sBuffer.Count;
		else return -1;
	}
	
	//Clear the send buffer
	static public void ClearSendBuffer(){
		if(theServer!=null)theServer.m_sBuffer.Clear();
		return;
	}
	
	//Check if a socket is still connected, questionable if this is working in Unity/Mono
	static bool isConnected(Socket socket){
		bool blockingState = socket.Blocking;
		bool connected = false;
		try
		{
		    byte [] tmp = new byte[1];
	
		    socket.Blocking = false;
		    socket.Send(tmp, 0, 0);
		    connected = true;
		}
		catch (SocketException e) 
		{
		    // 10035 == WSAEWOULDBLOCK
		    if (e.NativeErrorCode.Equals(10035))
		        connected = true;
		    else
		    {
		        connected = false;
		    }
		}
		finally
		{
		    socket.Blocking = blockingState;
		}
		return connected;
	}
}

Jeff

Override OnApplicationQuit and disconnect the socket there.
This is called when you hit Stop in play mode.

The easiest solution is to just not recompile while the game is playing.

When you change a script and compilation has finnished all scripts are being reloaded. This will clear out existing variables. So if you want to make sure the script continues working while playing and you recompile then, you can use OnEnable and OnDisable to recreate those variables before and after scripts are reloaded.

One question about the OnEnable/OnDisable. Do you mean to init or restore the variables in OnEnable and store the state in OnDisable?

Thanks!

Basically you want to do any cleanup in OnDisable.
In OnEnable you initialize your variables back.

OK I’ll give it a try, this will make tweaking scripts easier if it works.

Thanks!