public abstract class ClientBase
{
public class ProcessDataExecObj : IExecObj
{
private ClientBase m_client;
private int m_bytesReceived = 0;
public ProcessDataExecObj()
{
}
public ClientBase Client
{
set
{
m_client = value;
}
}
public int BytesReceived
{
get
{
return m_bytesReceived;
}
set
{
m_bytesReceived = value;
}
}
public void Execute()
{
m_client.OnReceive(m_bytesReceived);
m_client.ResumeReceive();
}
}
///
/// Default constructor
///
/// The server this client is connected to.
protected ClientBase(ServerBase server)
{
m_server = server;
m_readBuffer = BufferManager.Instance.CheckOut();
m_processDataObj = new ProcessDataExecObj();
m_processDataObj.Client = this;
}
#region Private variables
///
/// Total number of bytes that have been received by all clients.
///
private static volatile uint s_totalBytesReceived;
///
/// Total number of bytes that have been sent by all clients.
///
private static volatile uint s_totalBytesSent;
///
/// Number of bytes that have been received by this client.
///
private int m_bytesReceived;
///
/// Number of bytes that have been sent by this client.
///
private int m_bytesSent;
///
/// The socket containing the TCP connection this client is using.
///
protected Socket m_tcpSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
///
/// Pointer to the server this client is connected to.
///
protected ServerBase m_server;
///
/// The port the client should receive UDP datagrams on.
///
protected IPEndPoint m_udpEp;
///
/// The buffer containing the data received.
///
protected ArraySegment m_readBuffer;
///
/// The adjustment to make in the packet buffer.
///
protected int m_packetDelta;
///
/// The execution object for processing data.
///
protected ProcessDataExecObj m_processDataObj;
#endregion
#region Public properties
public ServerBase Server
{
get { return m_server; }
}
///
/// Gets the total number of bytes sent to all clients.
///
[CLSCompliant(false)]
public static uint TotalBytesSent
{
get { return s_totalBytesSent; }
}
///
/// Gets the total number of bytes received by all clients.
///
[CLSCompliant(false)]
public static uint TotalBytesReceived
{
get { return s_totalBytesReceived; }
}
///
/// Gets the IP address of the client.
///
public IPAddress TcpIP
{
get { return (m_tcpSock.RemoteEndPoint as IPEndPoint).Address; }
}
///
/// Gets the port the client is communicating on.
///
public int TcpPort
{
get { return (m_tcpSock.RemoteEndPoint as IPEndPoint).Port; }
}
///
/// Gets the port the client should receive UDP datagrams on.
///
public IPEndPoint UdpEndpoint
{
get { return m_udpEp; }
set { m_udpEp = value; }
}
///
/// Gets/Sets the socket this client is using for TCP communication.
///
public Socket TcpSocket
{
get { return m_tcpSock; }
set
{
if (m_tcpSock.Connected)
{
m_tcpSock.Shutdown(SocketShutdown.Both);
m_tcpSock.Close();
}
if (value != null)
{
m_tcpSock = value;
}
}
}
#endregion
///
/// Begins asynchronous TCP receiving for this client.
///
public void BeginReceive()
{
if (m_tcpSock.Connected)
{
using (SocketAsyncEventArgs args = new SocketAsyncEventArgs())
{
args.SetBuffer(m_readBuffer.Array, m_readBuffer.Offset, m_readBuffer.Count);
args.UserToken = this;
args.Completed += ReceiveAsyncComplete;
m_tcpSock.ReceiveAsync(args);
}
}
}
///
/// Resumes asynchronous TCP receiving for this client.
///
public void ResumeReceive()
{
using (SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs())
{
socketArgs.SetBuffer(m_readBuffer.Array, m_readBuffer.Offset + m_packetDelta, m_readBuffer.Count - m_packetDelta);
socketArgs.UserToken = this;
socketArgs.Completed += ReceiveAsyncComplete;
m_tcpSock.ReceiveAsync(socketArgs);
}
}
private static void ReceiveAsyncComplete(object sender, SocketAsyncEventArgs args)
{
ClientBase client = args.UserToken as ClientBase;
try
{
int bytesTransferred = args.BytesTransferred;
if (bytesTransferred == 0)
{
client.m_server.DisconnectClient(client, true);
}
else
{
unchecked
{
client.m_bytesReceived += bytesTransferred;
s_totalBytesReceived += (uint)bytesTransferred;
}
client.m_processDataObj.BytesReceived = bytesTransferred;
ThreadMgr.QueueExecObj(client.m_processDataObj);
}
}
catch (ObjectDisposedException e)
{
client.m_server.Warning(client, e);
client.m_server.DisconnectClient(client, true);
}
catch (Exception e)
{
client.m_server.Warning(client, e);
client.m_server.DisconnectClient(client, true);
}
}
///
/// Called when a packet has been received and needs to be processed.
///
/// The size of the packet in bytes.
protected abstract void OnReceive(int num_bytes);
}