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