Server

From Unify Community Wiki
Jump to: navigation, search

Server Script

The Server script opens a .NET socket on port 9349 (editable in the editor) and listens for incoming TCP connections. This was based on the server portion of the NetworkCursor script. This sends and receives arbitrary data through the connected sockets. It uses the System.Threads namespace to kick the server into its own system level thread instead of being a coroutine. If you are sending or receiving a lot of data this is quite useful.

C# Code

using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Text.RegularExpressions;
using System;
 
public class Server : MonoBehaviour {
	public int port = 9349;
	public bool debug = false;
 
    static Server theServer;
 
    private Socket m_Socket;
   	private Thread t;
 
	private Regex exp;
 
	bool myEnabled=false;
 
    ArrayList m_Connections;   
    ArrayList m_rBuffer;
	ArrayList m_sBuffers;
    ArrayList m_ByteBuffer;
	Hashtable robotListeners; //contains ArrayLists which hold the socket number of each connection listening to a given robot <key: robot name, value: ArrayList>
 
    void Start()
    {
		exp = new Regex(@"(\d+),(\w+),(\w+),(\w+),(.*)$"); //header is "<socketID>,<robotname>,<sensor/effector name>,<command>,<args>"
		myEnabled = gameObject.active;
		if(theServer==null) Init();
    }
 
    void Init(){
		if(theServer!=null) Cleanup();
		theServer = this;
		robotListeners = new Hashtable();
		if(m_Socket==null){		
			m_Connections = new ArrayList ();   
	    	m_rBuffer = new ArrayList ();
	    	m_ByteBuffer = new ArrayList ();
			m_sBuffers = new ArrayList ();
	        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);
 
			t = new Thread(new ThreadStart(ThreadWorker));
			t.Start();
	//		Debug.Log("Listening on: " + ((IPEndPoint)m_Socket.LocalEndPoint).Address + ":" + ((IPEndPoint)m_Socket.LocalEndPoint).Port);
		}
	}
 
	void SetEnabled(bool mode){
		myEnabled = mode;
		if(mode && theServer==null) Init();
		if(!mode) Cleanup();
	}
 
	void OnApplicationQuit(){
		Cleanup();
	}
 
    void Cleanup ()
    {		
		if (m_Socket != null){
//			m_Socket.Shutdown(SocketShutdown.Both);
            m_Socket.Close();
			m_Socket = null;
		}
 
		if(t!=null) t.Join();
 
		if(m_Connections!=null) {
			foreach (Socket con in m_Connections) if(con!=null) con.Close();
        	m_Connections.Clear();
			m_Connections=null;
		}
 
		if(t!=null) t=null;
		if(theServer!=null) theServer=null;
    }   
 
	//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 queues
	static public void PutMessage(string robotName, string sendMsg){
 
		if(theServer!=null && Connected()){
			ArrayList listeners = (ArrayList)(theServer.robotListeners[robotName]); //get a list of sockets listening to the robot sending the message
			if(listeners!=null && listeners.Count>0){
				if(theServer.debug) Debug.Log("Adding Message " + sendMsg + " to queues for " + robotName);				
				for(int i=0; i<listeners.Count; i++){ //for each listener, add the message to its outgoing buffer
					ArrayList m_sBuffer = (ArrayList) (theServer.m_sBuffers[(int)listeners[i]]);
					if(m_sBuffer==null) listeners.Remove(listeners[i]); //if a connection is dropped, m_sBuffer will be set to null elsewhere and we don't want to continue to use it.
					else{
						if(m_sBuffer.Count>100) m_sBuffer.Clear(); //if there is a backlog of more than 1000 messages clear the queue
						m_sBuffer.Add(sendMsg); //if everything is safe, add the message to the outgoing buffer
					}
				}
			}
			else if(listeners==null) Debug.Log("No one is in the listeners list for " + robotName);
			else Debug.Log ("Message not sent from " + robotName + " listerns.Count = " + listeners.Count);
		}
	}
 
	//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(){
		int backlog=0;
		if(theServer!=null){
			for(int i=0;i<theServer.m_sBuffers.Count;i++) backlog+=((ArrayList)(theServer.m_sBuffers[i])).Count;
			return backlog;
		}
		else return -1;
	}
 
	//Clear the send buffer
	static public void ClearSendBuffer(){
		if(theServer!=null) for(int i=0;i<theServer.m_sBuffers.Count;i++) ((ArrayList)(theServer.m_sBuffers[i])).Clear();
		return;
	}
 
	static private void FlushReadBuffer(Socket socket){
		socket.Receive(new byte[socket.Available]);
	}
 
	//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;
	}
 
 
	void ThreadWorker(){
		// double tTime = 0.0;
 
		while(m_Socket!=null && myEnabled) {	
			// tTime = Time.realtimeSinceStartup;
			try{	
				DoIO();
			}
			catch(Exception e){
				Debug.Log("Error in Server :: DoIO()\n" + e.StackTrace);
			}
			// Debug.Log("DoIO just took " + (Time.realtimeSinceStartup - tTime) + " seconds.");
			Thread.Sleep(10);
		}
	}
 
    void DoIO()  {
 		// Accept any incoming connections!
        ArrayList listenList = new ArrayList();
 
        if(m_Socket!=null) listenList.Add(m_Socket);
		else return;
 
        Socket.Select(listenList, null, null, 1000);
 
        for( int i = 0; i < listenList.Count; i++ ){
            Socket newSocket = ((Socket)listenList[i]).Accept();
			newSocket.Blocking=false;			
            m_Connections.Add(newSocket);
            m_ByteBuffer.Add(new ArrayList());
			m_sBuffers.Add(new ArrayList ());
            Debug.Log("Did connect " + newSocket.RemoteEndPoint);
        }
 
        // Read & Write data to the connections!
 
 
        if (m_Connections.Count > 0){
			// Write data to connections
			ArrayList connections = new ArrayList (m_Connections);
            Socket.Select(null, connections, null, 1000);
 
			for(int i=0; i<m_Connections.Count;i++){
				ArrayList m_sBuffer = (ArrayList) m_sBuffers[i];
 
				while (m_sBuffer.Count>0){
					if(debug) Debug.Log("Sending: " + m_sBuffer[0] + " from queue " + i);
 
					byte[] sndBytes = new byte[((string)m_sBuffer[0]).Length];
					string theString = (string)m_sBuffer[0];
					for(int j=0;j<sndBytes.Length;j++){
						sndBytes[j]=(byte)theString[j];
					}
					Socket socket = (Socket)connections[i];
					if(socket!=null){
						try{
							if(socket.Connected==false)break; 			
							socket.Send(sndBytes);		
						}
						catch (SocketException e) {
							if(debug) Debug.Log("Socket Exception " + e.NativeErrorCode + " " + e.Message);
							if(e.NativeErrorCode.Equals(10054) || e.NativeErrorCode.Equals(10058)){
								Debug.Log("Did Close");
								socket.Close();
								theServer.m_ByteBuffer.RemoveAt(m_Connections.IndexOf(socket));
								theServer.m_Connections.Remove(socket);
							}
							else if(debug) Debug.Log("Unhandled Socket Exception During Writing!");
						}
					}
					else if(debug) Debug.Log("Socket in connections[" + i + "] is null!");			
					m_sBuffer.RemoveAt(0); //Remove the message we just handled
				}
			}
 
			connections = new ArrayList (m_Connections);
			if(connections==null) return;
            Socket.Select(connections, null, null, 1000);
            // Go through all sockets that have data incoming!
            foreach (Socket socket in connections)
            {	
				ArrayList buffer = null;
				int socketIndex = m_Connections.IndexOf(socket);
 
				try{
					if(socket.Connected==true){
						byte[] receivedbytes = new byte[512];
 
						buffer = (ArrayList)m_ByteBuffer[socketIndex];
	                	int read = socket.Receive(receivedbytes);
 
						// print("chars Read: " + read + " char[0] = " + receivedbytes[0]);
 
						if(socket.Available>512) {
							FlushReadBuffer(socket);
							if(debug) Debug.Log("EMERGENCY! - Buffer Filling Up - Flushing");
						}
 
	                	if(receivedbytes[0]!=0) {
							for (int i=0;i<read;i++) buffer.Add(receivedbytes[i]);
						}
					}
					else if(debug) Debug.Log("Trying to read from socket, but it is no longer connected!");
				}
				catch (SocketException e) {
					if(e.NativeErrorCode.Equals(10054) || e.NativeErrorCode.Equals(10058)){
						if(debug) Debug.Log("Closing Socket Due to Socket Exception During Reading!");
						socket.Close();
						theServer.m_ByteBuffer.RemoveAt(m_Connections.IndexOf(socket));
						theServer.m_Connections.Remove(socket);
					}
					else if(debug) Debug.Log("Unhandled Socket Exception During Reading!");
 
				}
 
 
				while (buffer!=null && buffer.Count > 0){
					//   Debug.Log("buffer.Count " + buffer.Count);
                        ArrayList thismsgBytes = new ArrayList(buffer);
 
                        // if (thismsgBytes.Count != length) Debug.Log("Bug");
 
                        byte[] readbytes = (byte[])thismsgBytes.ToArray(typeof(byte));
 
						string readString = "";
 
						foreach(byte b in readbytes){
							if((char)b=='\n' || (char)b=='\r') {
								buffer.RemoveRange(0,1);
								break;
							}
							readString+=(char)b;						
						}
					//	print(readString.Length);
						if(readString.Length>0) buffer.RemoveRange(0, readString.Length);
 
						if(readString.Length>0){
							readString = socketIndex+","+readString;
							// if(length>0) print("From Server: Msg Length: "  + length);                        	
							if(m_rBuffer!=null)theServer.m_rBuffer.Add(readString);
							if(debug) Debug.Log("ReadString: " + readString);
						}
 
 
                        if (theServer != this) Debug.Log("Server Bug");   
                }
 
 
			}
		}
	}
 
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox