C # asynchronous Socket Tcp server implementation
Introduction
In c #, Microsoft has provided TcpListener and TcpClient to achieve Tcp communication, this Part has been written by some people to better Asynchronous Server code http://www.cnblogs.com/gaochundong/archive/2013/04/14/csharp_async_tcp_server.html this blogger wrote blog quality is really high, I often browse his blog and there is always a lot of surprises for me. He uses TcpListener to Implement Asynchronous servers.
In essence, my socket version is no different from his. I just changed it a little bit, so I just paste a piece of code here, so I will not explain it much.
Code server core code AsyncServer. cs
////// Asynchronous SOCKET server ///Public class AsyncServer: IDisposable {# region Fields ////// Maximum number of client connections allowed by the server program ///Private int _ maxClient ;////// Number of clients currently connected ///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 of the listener ///Public IPAddress Address {get; private set ;}///
/// Listening port ///Public int Port {get; private set ;}///
/// Encoding used for communication ///Public Encoding {get; set ;}# endregion # region Ctors ///
/// Asynchronous Socket TCP server //////
Listener Port public AsyncServer (int listenPort): this (IPAddress. Any, listenPort, 1024 ){}///
/// Asynchronous Socket TCP server //////
Listener endpoint public AsyncServer (IPEndPoint localEP): this (localEP. Address, localEP. Port, 1024 ){}///
/// Asynchronous Socket TCP server //////
IP address of the listener ///
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 //////
/// Maximum length of the suspended 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 Close the connection to all clients} return this ;}# endregion # region Receive ///
/// Process client connection //////
Private void HandleAcceptConnected (IAsyncResult ar) {if (IsRunning) {Socket server = (Socket) ar. asyncState; Socket client = server. endAccept (ar); // check whether 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); // triggers Client Connection events} session. recvDataBuffer = new byte [client. receiveBufferSize]; // starts to accept the Data client from this client. beginReceive (session. recvDataBuffer, 0, session. recvDataBuffer. length, SocketFlags. none, new AsyncCallback (HandleDataReceived), session);} // receives the next request server. beginAccept (new AsyncCallback (HandleAcceptConnected), ar. asyncState );}}///
/// Process client data //////
Private void HandleDataReceived (IAsyncResult ar) {if (IsRunning) {Session session = (Session) ar. asyncState; Socket client = session. clientSocket; try {// If asynchronous receiving is started twice, the client will execute EndReceive int recv = client twice when exiting. endReceive (ar); if (recv = 0) {// TODO trigger event (close client) CloseSession (session); RaiseNetError (session); return ;} // TODO processes read data ps: RaiseDataReceived (session) in the RecvDataBuffer of the session; // TODO triggers the Data Receiving Event} catch (SocketException ex) {// TODO Exception Handling RaiseNetError (session);} finally {// continue to receive data from the client. beginReceive (session. recvDataBuffer, 0, session. recvDataBuffer. length, SocketFlags. none, new AsyncCallback (HandleDataReceived), session) ;}}# endregion # region Send ///
/// Send data //////
Client Session for receiving data ///
Public void Send (Session session, byte [] data) {Send (session. ClientSocket, data );}///
/// Send data asynchronously to the specified client //////
Client ///
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 );}///
/// Processing function for data transmission completion //////
Target client Socket private void SendDataEnd (IAsyncResult ar) {(Socket) ar. AsyncState). EndSend (ar) ;}# endregion # region Events ///
/// Receives the data event ///Public event EventHandler
DataReceived; private void RaiseDataReceived (Session session) {if (DataReceived! = Null) {DataReceived (this, new AsyncEventArgs (session ));}}///
/// The connection to the client has been established ///Public event EventHandler ClientConnected ;///
/// Disconnection event with the client ///Public event EventHandler ClientDisconnected ;///
/// Trigger the client connection event //////
Private void RaiseClientConnected (Session session) {if (ClientConnected! = Null) {ClientConnected (this, new AsyncEventArgs (session ));}}///
/// Trigger the client connection 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 //////
Private void RaiseNetError (Session session) {if (NetError! = Null) {NetError (this, new AsyncEventArgs (session ));}}///
/// Exception event ///Public event EventHandler ServerException ;///
/// Trigger an exception //////
Private void RaiseServerException (Session session) {if (ServerException! = Null) {ServerException (this, new AsyncEventArgs (session) ;}# endregion # region Close ///
/// Close a session with the client //////
Public void CloseSession (Session session) {if (session! = Null) {session. datasync = null; session. recvDataBuffer = null; _ clients. remove (session); _ clientCount --; // TODO triggers closing event session. close ();}}///
/// Close all client sessions and disconnect from 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}
A Session class is used to encapsulate the connection Session to the client, cs
////// Session class between the client and the server ///Public class Session {# region field ////// Receiving data buffer ///Private byte [] _ recvBuffer ;////// The message sent from the client to the server // note: In some cases, the message may be a part of the message but not complete ///Private string _ datasync ;////// Client Socket ///Private Socket _ clientSock; # endregion # region attributes ////// Receiving data buffer ///Public byte [] RecvDataBuffer {get {return _ recvBuffer;} set {_ recvBuffer = value ;}}////// Access the session message ///Public string datasync {get {return _ datax;} set {_ datax = value ;}}////// Obtain the Socket object associated with the client session ///Public Socket ClientSocket {get {return _ clientSock; }}# endregion ////// Constructor //////The Socket used by the Session to connect to the public Session (Socket cliSock) {_ clientSock = cliSock ;}////// Close the session ///Public void Close () {// Close data receiving and sending _ clientSock. Shutdown (SocketShutdown. Both); // clear resource _ clientSock. Close ();}}
Event Type
Class AsyncEventArgs: EventArgs {////// Prompt message ///Public string _ msg; public Session _ sessions ;////// Whether it has 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 ;}}