- Home /
Threaded Socket Client with Thread-Safe Queue for Unity
I cannot seem to find a good example of using a thread for a socket and using some kind of queue for unity to check and see if there is data for the main thread.
I'm guessing there should be a thread that connects and than... -reads in data -check to make sure the data is complete via header information -adds it to some kind of thread safe queue of data -repeats until stopped or the socket closes from server
Have an outgoing thread as well...
UPDATE: Here's what I got so far, any suggesttions?
using UnityEngine;
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using System.Net.Sockets;
using System.Text;
public class ClientNetwork : MonoBehaviour {
public ClientGUI clientgui;
private static byte[] recievebuffer = new byte[1024];
private static int RecieveBufferSize = 0;
private static int SendBufferSize = 0;
private static Queue<string> RecieveQueue = new Queue<string>();
private static Queue<string> SendQueue = new Queue<string>();
private static readonly object SendQueueLocker = new object();
private static readonly object RecieveQueueLocker = new object();
private static readonly object SendBufferLocker = new object();
private static readonly object RecieveBufferLocker = new object();
private static readonly object SendThreadLocker = new object();
private static readonly object RecieveThreadLocker = new object();
private static bool RecieveThreadFree = true;
private static bool SendThreadFree = true;
private static bool RecieveQueueInUse = false;
private static bool SendQueueInUse = false;
private static bool wasPaused = false;
private bool socketReady = false;
private static Socket mySocket;
void OnGUI()
{
//GUILayout.Label(" Connected: "+ (socketReady && mySocket.Connected).ToString());
}
void CheckRecieve()
{
string msg = string.Empty;
lock(RecieveQueueLocker)
{
if (RecieveThreadFree && RecieveQueue.Count > 0)
{
msg = RecieveQueue.Dequeue();
}
}
if (!string.IsNullOrEmpty(msg))
{
if (msg.Length >= 2)
{
Debug.Log ("Message: " + msg);
switch (msg.Substring(0,2))
{
case "G:": //Packet is for the GUI Manager
clientgui.OnNetwork(msg.Substring(2));
break;
case "M:": //Packet is for the Map Manager
break;
default:
break;
}
} else
{
Debug.Log("Invalid Message Length:" + msg);
}
}
}
void Update()
{
CheckRecieve();
}
void OnApplicationQuit()
{
//closeSocket();
}
public bool setupSocket(string Host, int Port)
{
int attempts = 0;
try
{
attempts++;
mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
mySocket.Connect(Host, Port);
Debug.Log ("Connected.");
mySocket.BeginReceive(recievebuffer, 0, recievebuffer.Length, SocketFlags.None, new AsyncCallback(ReaderThread), mySocket);
Debug.Log ("Reader Thread Started.");
socketReady = true;
return true;
}
catch (Exception e)
{
Console.WriteLine("Connection attempts: " + attempts.ToString());
clientgui.OnNetwork("ER:" + e);
}
return false;
}
public bool Connected()
{
try
{
if (mySocket.Connected)
{
return true;
} else
{
return false;
}
}
catch (Exception e)
{
Debug.Log ("Socket Error on Connection Check");
//clientgui.OnNetwork("ER:" + e);
return false;
}
}
private static void ReaderThread (IAsyncResult AR)
{
try
{
//Socket socket = (Socket)AR.AsyncState;
Socket socket = mySocket;
int recieved = socket.EndReceive(AR);
byte[] dataBuf = new byte[recieved];
Array.Copy(recievebuffer, dataBuf, recieved);
string text = Encoding.ASCII.GetString(dataBuf);
lock(RecieveQueueLocker)
{
RecieveQueue.Enqueue(text);
}
try
{
mySocket.BeginReceive(recievebuffer, 0, recievebuffer.Length, SocketFlags.None, new AsyncCallback(ReaderThread), mySocket);
}
catch (Exception e)
{
Debug.Log("(Reader Thread: Start Next) Socket error: " + e);
//clientgui.OnNetwork("ER:" + e);
}
}
catch (Exception e)
{
Debug.Log("(Reader Thread: Begin) Socket error: " + e);
//clientgui.OnNetwork("ER:" + e);
}
}
private static void WriterThread (IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
socket.EndSend(AR);
}
public void WriteString(string theLine)
{
byte[] data = Encoding.ASCII.GetBytes(theLine);
try
{
mySocket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(WriterThread), mySocket);
Debug.Log("Sent: " + theLine);
}
catch (Exception e)
{
Debug.Log("(Network: WriteString) Socket error: " + e);
clientgui.OnNetwork("ER:" + e);
}
}
public void closeSocket()
{
if (!socketReady)
return;
try
{
mySocket.Close();
}
catch (Exception e)
{
Debug.Log("Close Socket Failed: " + e);
}
socketReady = false;
}
}
Unity Update() -Checks to see if the data queue has data in it -Uses the data -Remove that data from the queue. -Puts responses into an outgoing queue.
I don't know what or whatever would be usable in a thread and Unity. I'd like for it to have some kind of structure rather than just a string. I think I got the general idea of what needs to be done, I just not really sure how to start doing this. I'm sure someone has to have some example code somewhere, but I just cannot find it.
I know there are a lot of unused variables and stuff. This is a work in progress and I wasn't sure what I needed.