using UnityEngine;
using System.Collections;
using System;
using System.Net;
using System.Net.Sockets;
namespace tk
{
public class TcpClient : MonoBehaviour
{
public bool debug = false;
private Socket _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private byte[] _recieveBuffer = new byte[8142];
private TcpServer _server = null;
public delegate void OnDataRecv(byte[] data);
public OnDataRecv onDataRecvCB;
public delegate void OnConnected();
public OnConnected onConnectedCB;
// Flag to let us know a connection has dropped.
private bool dropped = false;
public float time_check_dropped = 0.0f;
public float time_check_dropped_freq = 3.0f;
///
/// Connect will establish a new TCP socket connection to a remote ip, port. This method is the first method
/// called to start using this object.
///
///
///
///
public bool Connect(string ip, int port)
{
if (_clientSocket.Connected)
return false;
try
{
IPAddress address = IPAddress.Parse(ip);
_clientSocket.Connect(new IPEndPoint(address, port));
}
catch (SocketException ex)
{
Debug.Log(ex.Message);
return false;
}
dropped = false;
_clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
return true;
}
///
/// OnServerAccept is an alternate form of client initialization that occurs when a server has accepted a client
/// connection already and passes that socket in clientSock in a connected state. This also then passes a pointer
/// to the server which can be used by the clients to broadcast messages to all the peers.
///
///
///
///
public bool OnServerAccept(Socket clientSock, TcpServer server)
{
if (!clientSock.Connected)
return false;
_clientSocket = clientSock;
_server = server;
dropped = false;
_clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
return true;
}
public void ClientFinishedConnect()
{
if(onConnectedCB != null)
onConnectedCB.Invoke();
}
public void ReleaseServer()
{
_server = null;
}
public void Disconnect()
{
try
{
if (_clientSocket.Connected)
{
_clientSocket.Shutdown(SocketShutdown.Both);
if (!IsDropped())
{
_clientSocket.Disconnect(true);
}
}
}
catch(SocketException e)
{
Debug.Log(e.ToString());
}
finally
{
_clientSocket.Close();
}
if (_server != null)
_server.RemoveClient(this);
}
void OnDestroy()
{
Disconnect();
}
public bool IsDropped()
{
return dropped;
}
public void Update()
{
// Update our drop detection...
if(_clientSocket != null && !IsDropped())
{
time_check_dropped += Time.deltaTime;
if(!_clientSocket.Connected)
{
dropped = true;
}
else if(time_check_dropped > time_check_dropped_freq)
{
time_check_dropped = 0.0f;
try
{
// this is the minimal form of message for a JsonTCPClient
string msg = "{}\n";
System.Text.Encoding encoding = System.Text.Encoding.Default;
_clientSocket.Send(encoding.GetBytes(msg));
}
catch(SocketException e)
{
Debug.LogWarning("connection dropped.");
dropped = true;
}
}
}
}
private void ReceiveCallback(IAsyncResult AR)
{
//Check how much bytes are recieved and call EndRecieve to finalize handshake
int recieved = 0;
try
{
recieved = _clientSocket.EndReceive(AR);
}
catch(SocketException e)
{
recieved = 0;
dropped = true;
Debug.LogWarning("Exception on recv. Connection dropped.");
}
if (recieved <= 0)
return;
//Copy the recieved data into new buffer , to avoid null bytes
byte[] recData = new byte[recieved];
Buffer.BlockCopy(_recieveBuffer, 0, recData, 0, recieved);
if (debug)
{
Debug.Log("recv:" + System.Text.Encoding.Default.GetString(recData));
}
//Process data here the way you want , all your bytes will be stored in recData
if (onDataRecvCB != null)
onDataRecvCB.Invoke(recData);
// Reset our drop connection test timer, since we just got data.
time_check_dropped = 0.0f;
//Start receiving again
_clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}
public bool SendData(byte[] data)
{
if (!_clientSocket.Connected)
return false;
SocketAsyncEventArgs socketAsyncData = new SocketAsyncEventArgs();
socketAsyncData.SetBuffer(data, 0, data.Length);
_clientSocket.SendAsync(socketAsyncData);
if (debug)
{
Debug.Log("sent:" + System.Text.Encoding.Default.GetString(data));
}
return true;
}
public bool SendDataToPeers(byte[] data)
{
if (!_clientSocket.Connected || _server == null)
return false;
_server.SendData(data, this);
return true;
}
public void SetDebug(bool _debug)
{
debug = _debug;
}
}
} //end namepace tk