C # Asynchronous socket TCP Server implementation

Source: Internet
Author: User
Asynchronous server implemented using TcpListener
Code

Server core code AsyncServer.cs

///
  
    /// Asynchronous SOCKET server
    ///
    public class AsyncServer: IDisposable
    {
  
        #region Fields
        ///
  
        /// The maximum number of client connections allowed by the server program
        ///
        private int _maxClient;
   
        ///
  
        /// Current number of connected clients
        ///
        private int _clientCount;
   
        ///
  
        /// Asynchronous socket used by the server
        ///
        private Socket _serverSock;
   
        ///
  
        /// Client session list
        ///
        private List _clients;
   
        private bool disposed = false;
  
        #endregion
  
  
        #region Properties
   
        ///
  
        /// Whether the server is running
        ///
        public bool IsRunning {get; private set;}
        ///
  
        /// IP address to monitor
        ///
        public IPAddress Address {get; private set;}
        ///
  
        /// Listening port
        ///
        public int Port {get; private set;}
        ///
  
        /// The encoding used for communication
        ///
        public Encoding Encoding {get; set;}
          
  
        #endregion
  
        #region Ctors
   
        ///
  
        /// Asynchronous Socket TCP server
        ///
        /// Listening port
        public AsyncServer (int listenPort)
            : this (IPAddress.Any, listenPort, 1024)
        {
        }
   
        ///
  
        /// Asynchronous Socket TCP server
        ///
        /// The endpoint of monitoring
        public AsyncServer (IPEndPoint localEP)
            : this (localEP.Address, localEP.Port, 1024)
        {
        }
   
        ///
  
        /// Asynchronous Socket TCP server
        ///
        /// IP address to monitor
        /// Listening port
        /// Maximum number of clients
        public AsyncServer (IPAddress localIPAddress, int listenPort, int maxClient)
        {
            this.Address = localIPAddress;
            this.Port = listenPort;
            this.Encoding = Encoding.Default;
   
            _maxClient = maxClient;
            _clients = new List ();
            _serverSock = new Socket (localIPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        }
  
        #endregion
  
  
        #region Server
   
        ///
  
        /// Start the server
        ///
        /// Asynchronous TCP server
        public AsyncServer Start ()
        {
            if (! IsRunning)
            {
                IsRunning = true;
                _serverSock.Bind (new IPEndPoint (this.Address, this.Port));
                _serverSock.Listen (1024);
                _serverSock.BeginAccept (new AsyncCallback (HandleAcceptConnected), _serverSock);
            }
            return this;
        }
   
        ///
  
        /// Start the server
        ///
        ///
        /// The maximum length of the pending connection sequence allowed by the server
        ///
        /// Asynchronous TCP server
        public AsyncServer Start (int backlog)
        {
            if (! IsRunning)
            {
                IsRunning = true;
                _serverSock.Bind (new IPEndPoint (this.Address, this.Port));
                _serverSock.Listen (backlog);
                _serverSock.BeginAccept (new AsyncCallback (HandleAcceptConnected), _serverSock);
            }
            return this;
        }
   
        ///
  
        /// Stop the server
        ///
        /// Asynchronous TCP server
        public AsyncServer Stop ()
        {
            if (IsRunning)
            {
                IsRunning = false;
                _serverSock.Close ();
                // TODO closes the connection to all clients
   
            }
            return this;
        }
  
        #endregion
  
        #region Receive
        ///
  
        /// Handle client connections
        ///
        ///
        private void HandleAcceptConnected (IAsyncResult ar)
        {
            if (IsRunning)
            {
                Socket server = (Socket) ar.AsyncState;
                Socket client = server.EndAccept (ar);
                   
                // Check if the maximum number of allowed clients is reached
                if (_clientCount == _maxClient)
                {
                    // TODO trigger event
                    RaiseServerException (null);
                }
                else
                {
                    Session session = new Session (client);
                    lock (_clients)
                    {
                        _clients.Add (session);
                        _clientCount ++;
                        RaiseClientConnected (session); // trigger client connection event
                    }
                    session.RecvDataBuffer = new byte [client.ReceiveBufferSize];
                    // Start accepting data from the client
                    client.BeginReceive (session.RecvDataBuffer, 0, session.RecvDataBuffer.Length, SocketFlags.None,
                     new AsyncCallback (HandleDataReceived), session);
                }
                // Accept the next request
                server.BeginAccept (new AsyncCallback (HandleAcceptConnected), ar.AsyncState);
            }
        }
        ////// Processing client data
        ///
        ///
        private void HandleDataReceived (IAsyncResult ar)
        {
            if (IsRunning)
            {
                Session session = (Session) ar.AsyncState;
                Socket client = session.ClientSocket;
                try
                {
                    // If the asynchronous reception is started twice, when the client exits
                    // EndReceive will be executed twice
                    int recv = client.EndReceive (ar);
                    if (recv == 0)
                    {
                        // TODO trigger event (close client)
                        CloseSession (session);
                        RaiseNetError (session);
                        return;
                    }
                    // TODO processes the data that has been read ps: the data is in the session's RecvDataBuffer
                    RaiseDataReceived (session);
                    // TODO triggers the data receiving event
                }
                catch (SocketException ex)
                {
                    // TODO exception handling
                    RaiseNetError (session);
                }
                finally
                {
                    // Continue to receive data from the client
                    client.BeginReceive (session.RecvDataBuffer, 0, session.RecvDataBuffer.Length, SocketFlags.None,
                     new AsyncCallback (HandleDataReceived), session);
                }
            }
        }
        #endregion
  
        #region Send
        ///
  
        /// send data  
        ///
        /// Client session that receives data
        /// Data message
        public void Send (Session session, byte [] data)
        {
            Send (session.ClientSocket, data);
        }
   
        ///
  
        /// Send data asynchronously to the specified client
        ///
        /// Client
        /// Message
        public void Send (Socket client, byte [] data)
        {
            if (! IsRunning)
                throw new InvalidProgramException ("This TCP Scoket server has not been started.");
   
            if (client == null)
                throw new ArgumentNullException ("client");
   
            if (data == null)
                throw new ArgumentNullException ("data");
            client.BeginSend (data, 0, data.Length, SocketFlags.None,
             new AsyncCallback (SendDataEnd), client);
        }
   
        ///
  
        /// Send data completion processing function
        ///
        /// Target client socket
        private void SendDataEnd (IAsyncResult ar)
        {
            ((Socket) ar.AsyncState) .EndSend (ar);
        }
        #endregion
  
        #region Events
        ///
  
        /// Received data event
        ///
        public event EventHandler DataReceived;
   
        private void RaiseDataReceived (Session session)
        {
            if (DataReceived! = null)
            {
                DataReceived (this, new AsyncEventArgs (session));
            }
        }
   
        ///
  
        /// The connection with the client has been established
        ///
        public event EventHandler ClientConnected;
        ///
  
        /// The connection with the client has been disconnected
        ///
        public event EventHandler ClientDisconnected;
   
        ///
  
        /// Trigger client connection event
        ///
        ///
        private void RaiseClientConnected (Session session)
        {
            if (ClientConnected! = null)
            {
                ClientConnected (this, new AsyncEventArgs (session));
            }
        }
        ///
  
        /// Trigger the client disconnection event
        ///
        ///
        private void RaiseClientDisconnected (Socket client)
        {
            if (ClientDisconnected! = null)
            {
                ClientDisconnected (this, new AsyncEventArgs ("disconnected"));
            }
        }
        ///
  
        /// Network error event
        ///
        public event EventHandler NetError;
        ///
  
        /// Trigger a network error event
        ///
        ///
        private void RaiseNetError (Session session)
        {
            if (NetError! = null)
            {
                NetError (this, new AsyncEventArgs (session));
            }
        }
   
        ///
  
        /// Abnormal events
        ///
        public event EventHandler ServerException;
        ///
  
        /// Trigger abnormal events
        ///
        ///
        private void RaiseServerException (Session session)
        {
            if (ServerException! = null)
            {
                ServerException (this, new AsyncEventArgs (session));
            }
        }
        #endregion
  
  
        #region Close
        ///
  
        /// Close a session with the client
        ///
        /// Client session object to be closed
        public void CloseSession (Session session)
        {
            if (session! = null)
            {
                session.Datagram = null;
                session.RecvDataBuffer = null;
   
                _clients.Remove (session);
                _clientCount--;
                // TODO triggers the close event
                session.Close ();
}
        }
        ///
  
        /// Close all client sessions and disconnect with all clients
        ///
        public void CloseAllClient ()
        {
            foreach (Session client in _clients)
            {
                CloseSession (client);
            }
            _clientCount = 0;
            _clients.Clear ();
        }
   
        ///
  
        /// Performs application-defined tasks associated with freeing,
        /// releasing, or resetting unmanaged resources.
        ///
        public void Dispose ()
        {
            Dispose (true);
            GC.SuppressFinalize (this);
        }
   
        ///
  
        /// Releases unmanaged and-optionally-managed resources
        ///
        /// true to release
        /// both managed and unmanaged resources; false
        /// to release only unmanaged resources.
        protected virtual void Dispose (bool disposing)
        {
            if (! this.disposed)
            {
                if (disposing)
                {
                    try
                    {
                        Stop ();
                        if (_serverSock! = null)
                        {
                            _serverSock = null;
                        }
                    }
                    catch (SocketException ex)
                    {
                        // TODO
                        RaiseServerException (null);
                    }
                }
                disposed = true;
            }
        }
        #endregion
    }
It uses a Session class to encapsulate the connection to the client

Session, cs

///
  
    /// Session class between client and server
    ///
    public class Session
    {
        #region field
        ///
  
        /// Receive data buffer
        ///
        private byte [] _recvBuffer;
   
        ///
  
        /// Messages sent by the client to the server
        /// Note: In some cases the message may only be a fragment of the message and not complete
        ///
        private string _datagram;
   
        ///
  
        /// Client's Socket
        ///
        private Socket _clientSock;
  
        #endregion
  
        #region attribute
   
        ///
  
        /// Receive data buffer
        ///
        public byte [] RecvDataBuffer
        {
            get
            {
                return _recvBuffer;
            }
            set
            {
                _recvBuffer = value;
            }
        }
   
        ///
  
        /// Access the session message
        ///
        public string Datagram
        {
            get
            {
                return _datagram;
            }
            set
            {
                _datagram = value;
            }
        }
   
        ///
  
        /// Get the Socket object associated with the client session
        ///
        public Socket ClientSocket
        {
            get
            {
                return _clientSock;
   
            }
        }
  
  
        #endregion
   
        ///
  
        /// Constructor  
        ///
        /// Socket connection used by the session
        public Session (Socket cliSock)
        {
   
            _clientSock = cliSock;
        }
        ///
  
        /// Close the session
        ///
        public void Close ()
        {
   
            // Close the receiving and sending of data
            _clientSock.Shutdown (SocketShutdown.Both);
   
            // Clean up resources
            _clientSock.Close ();
        }
    }
Event class

class AsyncEventArgs: EventArgs
    {
        ///
  
        /// Prompt information
        ///
        public string _msg;
   
        public Session _sessions;
   
        ///
  
        /// Has it been processed
        ///
        public bool IsHandled {get; set;}
   
        public AsyncEventArgs (string msg)
        {
            this._msg = msg;
            IsHandled = false;
        }
        public AsyncEventArgs (Session session)
        {
            this._sessions = session;
            IsHandled = false;
        }
        public AsyncEventArgs (string msg, Session session)
        {
            this._msg = msg;
            this._sessions = session;
            IsHandled = false;
        }
    }


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.