< Intro To Server/Listening Socket | Main | VB .NET Asynchronous Class Example >

 


 

Chapter 9 Part 2:

Server or Listening Sockets Programming

 

 

What do we have in this chapter 9 Part 2?

  1. A Simple C# Asynchronous Class Example

 

 

A Simple C# Asynchronous Class Example

 

In this example, we will create a shared asynchronous packet class that will be used by the C# and VB .NET server and client programs that will be created later. Create a new class library project and you might want to use AsyncPacketClass as the project and AsyncPacketClassCS as the solution names as shown in the following Figure.

 

A Simple C# Asynchronous Class Example - craeating a new class library project in Visual Studio 2008

 

Next, rename the source file to AsyncPacket to reflect the application that we are going to develop.

 

A Simple C# Asynchronous Class Example - renaming the source file to AsyncPacket to reflect the application

 

Then, rename the first default class definition to IoPacket.

 

A Simple C# Asynchronous Class Example - renaming the first default class given

 

Add the following code for the IoPacketType enum, IoPacket class and several other classes.

 

// This file contains common class definitions used by both the client

// and server asynchronous code samples. This file contains classes

// used as the context information associated with each asynchronous

// operation posted.

 

using System;

using System.Net;

using System.Net.Sockets;

using System.Collections;

using System.Threading;

 

namespace AsyncPacketClass

{

    /// <summary>

    /// Indicates the type of asynchronous operation.

    /// </summary>

    public enum IoPacketType

    {

        Accept,

        Connect,

        Send,

        SendTo,

        Receive,

        ReceiveFrom

    }

 

    /// <summary>

    /// Describes an IO asynchronous IO request. This class contains the delegate which

    /// is fired when the specified operation completes. It also allocates the data

    /// buffer used by a send or receive operation.

    /// </summary>

    public class IoPacket

    {

        public IoPacketType ioType;

        public SocketConnection connObject;

        public AsyncCallback ioCallback;

        public byte[ ] dataBuffer;

        public const int IoPacketDefaultBufferSize = 4096;

 

        /// <summary>

        /// Initialize member variables and allocate the data buffer if this IO packet

        /// describes an asynchronous send or receive operation.

        /// </summary>

        /// <param name="connObj">Connection object to which this IO packet belongs to</param>

        /// <param name="packetType">Operation type being created</param>

        public IoPacket(SocketConnection connObj, IoPacketType packetType)

        {

            ioType = packetType;

            connObject = connObj;

            ioCallback = new AsyncCallback(IoCompleteCallback);

 

            // If this packet describes a send or receive operation create the

            // data buffer.

            if (packetType != IoPacketType.Accept)

            {

                dataBuffer = new byte[IoPacketDefaultBufferSize];

            }

        }

 

        /// <summary>

        /// Posts an asynchronous connect operation on the underlying TCP socket.

        /// </summary>

        /// <param name="serverEndPoint"></param>

        public void PostConnect(IPEndPoint serverEndPoint)

        {

            try

            {

                connObject.tcpSocket.BeginConnect(serverEndPoint, ioCallback, this);

                connObject.IncrementOutstanding(ioType);

                // Console.WriteLine("Posting a BeginConnect...");

            }

            catch (SocketException err)

            {

                Console.WriteLine("IoPacket.PostConnect: {0}", err.Message);

                throw;

            }

        }

 

        /// <summary>

        /// Posts an asynchronous accept operation on the underlying TCP socket.

        /// </summary>

        public void PostAccept()

        {

            try

            {

                // Post the async accept and increment the accept count

                connObject.tcpSocket.BeginAccept(ioCallback, this);

                connObject.IncrementOutstanding(ioType);

                //Console.WriteLine("Posting a BeginAccept...");

            }

            catch (SocketException err)

            {

                Console.WriteLine("IoPacket.PostAccept: {0}", err.Message);

                throw;

            }

        }

 

        /// <summary>

        /// Posts an asynchronous receive operation on the underlying TCP socket.

        /// </summary>

        public void PostReceive()

        {

            try

            {

                // Post the async receive and increment the accept count

                connObject.tcpSocket.BeginReceive(

                    dataBuffer,

                    0,

                    dataBuffer.Length,

                    SocketFlags.None,

                    ioCallback,

                    this

                    );

                connObject.IncrementOutstanding(ioType);

                //Console.WriteLine("Posting a BeginReceive...");

            }

            catch (SocketException err)

            {

                Console.WriteLine("IoPacket.BeginReceive: {0}", err.Message);

                throw;

            }

        }

 

        /// <summary>

        /// Posts an asynchronous send operation on the underlying TCP socket.

        /// </summary>

        public void PostSend()

        {

            try

            {

                // Post an async send and increment the send count

                connObject.tcpSocket.BeginSend(

                    dataBuffer,

                    0,

                    dataBuffer.Length,

                    SocketFlags.None,

                    ioCallback,

                    this

                    );

                connObject.IncrementOutstanding(ioType);

                //Console.WriteLine("Posting a BeginSend...");

            }

            catch (SocketException err)

            {

                Console.WriteLine("IoPacket.BeginSend: {0}", err.Message);

                throw;

            }

        }

 

        /// <summary>

        /// This is the asynchronous delegate that is called when an operation on the posted

        /// IO object completes. This method simply calls the owning objects HandleIo method.

        /// Only object derived from the SocketConnection class can use this IoPacket class

        /// for describing async IO operations.

        /// </summary>

        /// <param name="ar">Asynchronous context information</param>

        static void IoCompleteCallback(IAsyncResult ar)

        {

            IoPacket ioOperation = (IoPacket)ar.AsyncState;

 

            ioOperation.connObject.DecrementOutstanding(ioOperation.ioType);

            ioOperation.connObject.HandleIo(ioOperation, ar);

        }

    }

 

    /// <summary>

    /// Base class from which the TcpServer and ClientConnection objects are derived

    /// from.

    /// </summary>

    abstract public class SocketConnection

    {

        public Socket tcpSocket;

        public IPEndPoint tcpAddress;

        protected int receiveOutstanding;

        protected int receiveFromOutstanding;

        protected int sendOutstanding;

        protected int sendToOutstanding;

        protected int connectOutstanding;

        protected int acceptOutstanding;

        protected int sendByteCount;

        protected int receiveByteCount;

 

        /// <summary>

        /// Simple constructor to initialize counters to zero.

        /// </summary>

        public SocketConnection()

        {

            receiveOutstanding = 0;

            receiveFromOutstanding = 0;

            sendOutstanding = 0;

            sendToOutstanding = 0;

            connectOutstanding = 0;

            acceptOutstanding = 0;

            sendByteCount = 0;

            receiveByteCount = 0;

        }

 

        /// <summary>

        /// Returns the total bytes sent on the socket.

        /// </summary>

        public int TotalSendBytes

        {

            get

            {

                return sendByteCount;

            }

        }

 

        /// <summary>

        /// Returns the total bytes received on the socket.

        /// </summary>

        public int TotalReceiveBytes

        {

            get

            {

                return receiveByteCount;

            }

        }

 

        /// <summary>

        /// This method handles the IO operation that completed.

        /// </summary>

        /// <param name="io">Object describing the IO operation that completed</param>

        /// <param name="ar">Asynchronous context information</param>

        abstract public void HandleIo(IoPacket io, IAsyncResult ar);

 

        /// <summary>

        /// Removes the indicated IO packet from any lists or queues the packet may be in

        /// </summary>

        /// <param name="io">IO object to remove from any lists</param>

        abstract public void RemoveIo(IoPacket io);

 

        /// <summary>

        /// Increments the count for the outstanding operation type. This is implemented such

        /// that the IoPacket post routines can make a call to increment the count such that

        /// the caller of each post routine doesn't have to make the increment call.

        /// </summary>

        /// <param name="ioType">Operation type to increment count for</param>

        public void IncrementOutstanding(IoPacketType ioType)

        {

            switch (ioType)

            {

                case IoPacketType.Connect:

                    Interlocked.Increment(ref connectOutstanding);

                    break;

                case IoPacketType.Accept:

                    Interlocked.Increment(ref acceptOutstanding);

                    break;

                case IoPacketType.Receive:

                    Interlocked.Increment(ref receiveOutstanding);

                    break;

                case IoPacketType.ReceiveFrom:

                    Interlocked.Increment(ref receiveFromOutstanding);

                    break;

                case IoPacketType.Send:

                    Interlocked.Increment(ref sendOutstanding);

                    break;

                case IoPacketType.SendTo:

                    Interlocked.Increment(ref sendToOutstanding);

                    break;

                default:

                    break;

            }

        }

 

        /// <summary>

        /// Decrements the count for the outstanding operation type. This is implemented such

        /// that the IoPacket post routines can make a call to decrement the count such that

        /// the caller of each post routine doesn't have to make the decrement call.

        /// </summary>

        /// <param name="ioType">Operation type to decrement count for</param>

        public void DecrementOutstanding(IoPacketType ioType)

        {

            switch (ioType)

            {

                case IoPacketType.Connect:

                    Interlocked.Decrement(ref connectOutstanding);

                    break;

                case IoPacketType.Accept:

                    Interlocked.Decrement(ref acceptOutstanding);

                    break;

                case IoPacketType.Receive:

                    Interlocked.Decrement(ref receiveOutstanding);

                    break;

                case IoPacketType.ReceiveFrom:

                    Interlocked.Decrement(ref receiveFromOutstanding);

                    break;

                case IoPacketType.Send:

                    Interlocked.Decrement(ref sendOutstanding);

                    break;

                case IoPacketType.SendTo:

                    Interlocked.Decrement(ref sendToOutstanding);

                    break;

                default:

                    break;

            }

        }

    }

        /// <summary>

        /// This class identifies a client connection. It keeps track of all outstanding

        /// async send and receive operations and handles completed IO operations.

        /// </summary>

        public class ClientConnection : SocketConnection

        {

            private ArrayList ownerList;

            private ManualResetEvent ownerEvent;

            private ArrayList sendList;

            private ArrayList recvList;

            private int sendCountLeft;

            private IoPacket connectPacket;

 

            /// <summary>

            /// This is the constructor for the client which takes only the client socket

            /// object. It creates the lists of outstanding send and receive operations

            /// and posts the initial BeginReceive.

            /// </summary>

            /// <param name="tcpClient">Socket object representing the client connection</param>

            /// <param name="serverObject">Reference to the server object that owns this client connection</param>

            public ClientConnection(IPEndPoint serverEndPoint, ArrayList clientList, ManualResetEvent clientEmpty) : base()

            {

                ownerList = clientList;

                ownerEvent = clientEmpty;

 

                sendList = new ArrayList();

                recvList = new ArrayList();

 

                sendCountLeft = 15;

 

                tcpSocket = new Socket(

                    serverEndPoint.AddressFamily,

                    SocketType.Stream,

                    ProtocolType.Tcp

                    );

 

                connectPacket = new IoPacket(this, IoPacketType.Connect);

 

                try

                {

                    connectPacket.PostConnect(serverEndPoint);

                }

                catch (Exception err)

                {

                    Console.WriteLine("ClientConnection: PostConnect failed: {0}", err.Message);

                }

            }

 

 

 

            /// <summary>

            /// This overridden routine handles all asynchronous IO that completes on the ClientConnection

            /// object. Since the client only sends and receives only the Send and Receive commands are

            /// handled. The client connection first receives a request from the client until the client

            /// shuts down the send path. At this point the client connection will receive zero bytes

            /// indicating the client is done sending. This is followed by the client sending a response

            /// to the client. Once the requested number of send operations are performed to the client

            /// the client socket is closed and resources are freed (by closing the socket handle and

            /// indicating to the owning TcpServer to remove the ClientConnection object from its list

            /// of connections).

            /// </summary>

            /// <param name="io">IO packet object that describes the completed operation</param>

            /// <param name="ar">Asynchronous context information for the completed operation</param>

            public override void HandleIo(IoPacket io, IAsyncResult ar)

            {

                int rc;

 

                switch (io.ioType)

                {

                    case IoPacketType.Connect:

                        // Connect operation completed

                        try

                        {

                            tcpSocket.EndConnect(ar);

 

                            // Add the IoPacket to the send list

                            sendList.Add(io);

                            // Make it a send operation and post a send operation

                            io.ioType = IoPacketType.Send;

                            io.PostSend();

                        }

                        catch (Exception err)

                        {

                            Console.WriteLine("Socket connect failed: {0}", err.Message);

                            tcpSocket.Close();

                            ownerList.Remove(this);

                            ownerEvent.Set();

                        }

                        break;

                    case IoPacketType.Send:

                        // An async send operation completed, first decrement the number of sends left

                        Interlocked.Decrement(ref sendCountLeft);

 

                        try

                        {

                            // Get the results from the send

                            rc = tcpSocket.EndSend(ar);

                            // Update counters

                            sendByteCount += rc;

 

                            // Console.WriteLine("Client wrote {0} bytes", rc);

 

                            // Check to see if we're done sending, if so close the socket and clean

                            //    up the IoPacket used.

                            if (sendCountLeft == 0)

                            {

                                // Console.WriteLine("Shutting down connection");

 

                                tcpSocket.Shutdown(SocketShutdown.Send);

                                RemoveIo(io);

                                io.ioType = IoPacketType.Receive;

                                recvList.Add(io);

                                io.PostReceive();

                            }

                            else

                            {

                                // If there are still sends left, post another async send operation

                                io.PostSend();

                            }

                        }

                        catch (Exception err)

                        {

                            Console.WriteLine("ClientConnection.HandleIo: Send op failed: {0}", err.Message);

                            tcpSocket.Close();

                            ownerList.Remove(this);

                            ownerEvent.Set();

                        }

                        break;

                    case IoPacketType.Receive:

                        // An async receive operation completed

                        try

                        {

                            // Get the results from the operation

                            rc = tcpSocket.EndReceive(ar);

 

                            // Update the byte counters

                            receiveByteCount += rc;

 

                            // Console.WriteLine("Client read {0} bytes", rc);

                            // If zero bytes were returned, the client has shutdown its send side. This

                            //    side then initiates sending data back to the client.

                            if (rc == 0)

                            {

                                // Console.WriteLine("Client connection shutdown...");

                                // Once the entire request is received start the response

                                RemoveIo(io);

                                tcpSocket.Close();

                                ownerList.Remove(this);

                                ownerEvent.Set();

                            }

                            else

                            {

                                // Client hasn't finished sending data so post another async receive

                                io.PostReceive();

                            }

                        }

                        catch (Exception err)

                        {

                            // Clean up the client connection if a receive fails

                            Console.WriteLine("ClientConnection.HandleIo: Receive op failed: {0}", err.Message);

                            tcpSocket.Close();

                            ownerList.Remove(this);

                            ownerEvent.Set();

                        }

                        break;

                    default:

                        // Should never be here

                        Console.WriteLine("ClientConnection.HandleIo: Accept indication received ?!?!");

                        break;

                }

            }

 

            /// <summary>

            /// Removes the given IoPacket from the appropriate ArrayList depending on the operation

            /// type.

            /// </summary>

            /// <param name="io">IO object to remove from any lists</param>

            public override void RemoveIo(IoPacket io)

            {

                switch (io.ioType)

                {

                    case IoPacketType.Receive:

                        recvList.Remove(io);

                        break;

                    case IoPacketType.Send:

                        sendList.Remove(io);

                        break;

                    default:

                        break;

                }

                io = null;

            }

        }

 

        /// <summary>

        /// This class identifies a client connection. It keeps track of all outstanding

        /// async send and receive operations and handles completed IO operations.

        /// </summary>

        public class AcceptConnection : SocketConnection

        {

            private ArrayList sendList;

            private ArrayList recvList;

            private TcpServer tcpParent;

            private int sendCountLeft;

 

            /// <summary>

            /// This is the constructor for the client which takes only the client socket

            /// object. It creates the lists of outstanding send and receive operations

            /// and posts the initial BeginReceive.

            /// </summary>

            /// <param name="tcpClient">Socket object representing the client connection</param>

            /// <param name="serverObject">Reference to the server object that owns this client connection</param>

            public AcceptConnection(Socket tcpClient, TcpServer serverObject) : base()

            {

                tcpSocket = tcpClient;

                sendList = new ArrayList();

                recvList = new ArrayList();

                tcpParent = serverObject;

 

                sendCountLeft = 15;

                Console.WriteLine("Client connection from: {0}", tcpSocket.RemoteEndPoint.ToString());

                // Post the initial BeginReceive on the client socket

                IoPacket recvPacket = new IoPacket(this, IoPacketType.Receive);

                recvList.Add(recvPacket);

 

                try

                {

                    recvPacket.PostReceive();

                }

                catch (Exception err)

                {

                    Console.WriteLine("AcceptConnection.ClientConnection: PostReceive failed: {0}", err.Message);

                }

            }

 

            /// <summary>

            /// This overridden routine handles all asynchronous IO that completes on the ClientConnection

            /// object. Since the client only sends and receives only the Send and Receive commands are

            /// handled. The client connection first receives a request from the client until the client

            /// shuts down the send path. At this point the client connection will receive zero bytes

            /// indicating the client is done sending. This is followed by the client sending a response

            /// to the client. Once the requested number of send operations are performed to the client

            /// the client socket is closed and resources are freed (by closing the socket handle and

            /// indicating to the owning TcpServer to remove the ClientConnection object from its list

            /// of connections).

            /// </summary>

            /// <param name="io">IO packet object that describes the completed operation</param>

            /// <param name="ar">Asynchronous context information for the completed operation</param>

            public override void HandleIo(IoPacket io, IAsyncResult ar)

            {

                int rc;

 

                switch (io.ioType)

                {

                    case IoPacketType.Send:

                         // An async send operation completed, first decrement the number of sends left

                        Interlocked.Decrement(ref sendCountLeft);

 

                        try

                        {

                            // Get the results from the send

                            rc = tcpSocket.EndSend(ar);

                            // Update counters

                            sendByteCount += rc;

                            tcpParent.IncrementByteCount(rc, 0);

                            // Console.WriteLine("Client wrote {0} bytes", rc);

                            // Check to see if we're done sending, if so close the socket and clean

                            //    up the IoPacket used.

                            if (sendCountLeft == 0)

                            {

                                tcpSocket.Shutdown(SocketShutdown.Send);

                                tcpSocket.Close();

                                RemoveIo(io);

                                io = null;

                                tcpSocket = null;

                                // Console.WriteLine("Connection finished...");

                            }

                            else

                            {

                                // If there are still sends left, post another async send operation

                                io.PostSend();

                            }

                        }

                        catch (Exception err)

                        {

                            Console.WriteLine("AcceptConnection.HandleIo: Send op failed: {0}", err.Message);

                            tcpSocket.Close();

                            tcpSocket = null;

                        }

                        finally

                        {

                            // Check to see if the client connection is done, if so indicate to the TcpServer

                            //     parent to remove the client from its list.

 

                            // Console.WriteLine("sendCountLeft = {0} | sendOutstanding = {1} | recvOutstanding = {2}",

                            //    sendCountLeft,

                            //    sendOutstanding,

                            //    base.receiveOutstanding

                            //    );

 

                            if ((tcpSocket == null) && (sendCountLeft == 0) && (sendOutstanding == 0) && (receiveOutstanding == 0))

                            {

                                tcpParent.RemoveClient(this);

                            }

                        }

                        break;

                    case IoPacketType.Receive:

                        // An async receive operation completed

                         try

                        {

                            // Get the results from the operation

                            rc = tcpSocket.EndReceive(ar);

                            // Update the byte counters

                            receiveByteCount += rc;

                            tcpParent.IncrementByteCount(0, rc);

                            // Console.WriteLine("Client read {0} bytes", rc);

                            // If zero bytes were returned, the client has shutdown its send side. This

                            //    side then initiates sending data back to the client.

                            if (rc == 0)

                            {

                                //Console.WriteLine("Client connection shutdown...");

                                // Once the entire request is received start the response

                                RemoveIo(io);

                                // Switch the packet type to sending

                                io.ioType = IoPacketType.Send;

                                sendList.Add(io);

                                // Post a send operation to the client

                                io.PostSend();

                            }

                            else

                            {

                                // Client hasn't finished sending data so post another async receive

                                io.PostReceive();

                            }

                        }

                        catch (Exception err)

                        {

                            // Clean up the client connection if a receive fails

                            Console.WriteLine("ClientConnection.HandleIo: Receive op failed: {0}", err.Message);

                            tcpSocket.Close();

                            tcpSocket = null;

                            tcpParent.RemoveClient(this);

                        }

                        break;

                    default:

                         // Should never be here

                        Console.WriteLine("AcceptConnection.HandleIo: Accept indication received ?!?!");

                        break;

                }

            }

 

            /// <summary>

            /// Removes the given IoPacket from the appropriate ArrayList depending on the operation

            /// type.

            /// </summary>

            /// <param name="io">IO object to remove from any lists</param>

            public override void RemoveIo(IoPacket io)

            {

                switch (io.ioType)

                {

                    case IoPacketType.Receive:

                        recvList.Remove(io);

                        break;

                    case IoPacketType.Send:

                        sendList.Remove(io);

                        break;

                    default:

                        break;

                }

                io = null;

            }

        }

 

        /// <summary>

        /// This class encapsulates functionality for the TCP server object. This

        /// class keeps track of all clients accepted on the listening socket

        /// as well as the outstanding asynchronous accept operations. The class

        /// keeps track the send and receive byte counters and client counts.

        /// </summary>

        public class TcpServer : SocketConnection

        {

            private ArrayList clientList,  clientSyncList;

            private ArrayList acceptList;

            private int serverShutdown;

            public ManualResetEvent serverDone;

            public int totalClientCount;

            public int currentClientCount;

 

            /// <summary>

            /// Simple constructor for the TcpServer class. This initializes the counters

            /// and creates the listening TCP socket.

            /// </summary>

            /// <param name="listenEndPoint">Endpoint to create the listening socket on</param>

            /// <param name="asyncListenLimit">Maximum number of async accepts outstanding</param>

            public TcpServer(IPEndPoint listenEndPoint, int asyncListenLimit) : base()

            {

                int optval = 1;

 

                // Initialize some member variables                       

                serverShutdown = 0;

                totalClientCount = 0;

                currentClientCount = 0;

                serverDone = new ManualResetEvent(false);

 

                // Create the listening socket

                tcpSocket = new Socket(

                    listenEndPoint.AddressFamily,

                    SocketType.Stream,

                    ProtocolType.Tcp

                    );

 

                // Set exclusive use so that the port we bind to cannot be stolen by anyone else

                tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, optval);

                // Bind the socket to the specified address and port

                tcpSocket.Bind(listenEndPoint);

                // Set the socket to listening

                tcpSocket.Listen(int.MaxValue);

                // Indicate what address/port socket is listening on

                Console.WriteLine("Listening on {0}", listenEndPoint.ToString());

                // Create list for outstanding client connections

                clientList = new ArrayList();

                clientSyncList = ArrayList.Synchronized(clientList);

                // Create list for outstanding BeginAccept operations

                acceptList = new ArrayList();

                // Post the initial BeginAccepts on the listening socket

                for (int i = 0; i < asyncListenLimit; i++)

                {

                    IoPacket acceptPacket = new IoPacket(this, IoPacketType.Accept);

                    acceptList.Add(acceptPacket);

                    try

                    {

                        acceptPacket.PostAccept();

                    }

                    catch (Exception err)

                    {

                        Console.WriteLine("TcpServer.TcpServer: PostAccept failed: {0}", err.Message);

                    }

                }

            }

 

            /// <summary>

            /// This method removes an accepted client object (AcceptConnection) from the

            /// list of accepted connections. It decrements the current client count.

            /// </summary>

            /// <param name="clientObject">Accepted client object to remove</param>

            public void RemoveClient(AcceptConnection clientObject)

            {

                clientSyncList.Remove(clientObject);

                clientObject = null;

                Interlocked.Decrement(ref currentClientCount);

            }

 

            /// <summary>

            /// This method marks the TcpServer as shutting down. This flag is set before all the

            /// listening sockets are closed.

            /// </summary>

            public void Shutdown()

            {

                Interlocked.Increment(ref serverShutdown);

            }

 

            /// <summary>

            /// This routine handles all IO completion events initiated by the TcpServer

            /// listening socket which will consist of BeginAccept events. Before accessing

            /// the socket, a check is made to make sure the server is not shutting down

            /// in which case the listening socket have already been closed.

            /// </summary>

            /// <param name="io">IO packet describing the operation that completed</param>

            /// <param name="ar">Asynchronous context information</param>

            public override void HandleIo(IoPacket io, IAsyncResult ar)

            {

                switch (io.ioType)

                {

                    case IoPacketType.Accept:

                        // Console.WriteLine("TcpServer.HandleIo: Accept completed: outstanding {0}", acceptOutstanding );

                        if (serverShutdown != 0)

                        {

                            io.connObject.RemoveIo(io);

                            return;

                        }

 

                        try

                        {

                            Socket clientSocket;

                            AcceptConnection clientConn;

 

                            try

                            {

                                // Handle the accept that completed

                                clientSocket = tcpSocket.EndAccept(ar);

                                clientConn = new AcceptConnection(clientSocket, this);

                                clientSyncList.Add(clientConn);

                                // Update the counters

                                Interlocked.Increment(ref totalClientCount);

                                Interlocked.Increment(ref currentClientCount);

                            }

                            catch

                            {

                                Console.WriteLine("Accept: Client aborted connection most likely...");

                            }

                            // Repost the accept

                            io.PostAccept();

                        }

                        catch (Exception err)

                        {

                            Console.WriteLine("TcpServer.HandleIo: Unknown error: {0}", err.Message);

                            acceptList.Remove(io);

                            io = null;

                        }

                        break;

                    default:

                        break;

                }

            }

 

            /// <summary>

            /// This method removes the IoPacket from the appropriate list.

            /// </summary>

            /// <param name="io">The IoPacket to remove from the correct list</param>

            public override void RemoveIo(IoPacket io)

            {

                switch (io.ioType)

                {

                    case IoPacketType.Accept:

                        acceptList.Remove(io);

                        io = null;

                        break;

                    default:

                        break;

                }

            }

           

            /// <summary>

            /// Increments the sent and received byte counts for all client connections established

            /// on this TCP server socket. Each AcceptConnection has a reference to the TcpServer

            /// on which the client connection was accepted -- it then calls this method to

            /// increment the byte counters.

            /// </summary>

            /// <param name="sendCount">Number of bytes sent to increment counter by</param>

            /// <param name="recvCount">Number of bytes received to increment counter by</param>

            public void IncrementByteCount(int sendCount, int recvCount)

            {

                base.sendByteCount += sendCount;

                base.receiveByteCount += recvCount;

            }

        }

}

 

 

Build the project and make sure there is no error that can be seen in the Output window.

 

A Simple C# Asynchronous Class Example - building the class library project

 

The generated DLL file that will be used in the next client and server programs is shown below.

 

A Simple C# Asynchronous Class Example - the generated DLL file that ready to be used as shared library

 

 

 


 

< Intro To Server/Listening Socket | Main | VB .NET Asynchronous Class Example >