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); }