Serguei Fedorov
Serguei Fedorov

Reputation: 7913

Understanding the Async (sockets) in C#

I am a little bit confused about what does the Async approach achieve. I encountered it when looking up how to make a server accept multiple connections. What confuses me while looking up what Aync does in C# exactly, is that from what I can tell its not its own thread. However, it also allows you to avoid locking and stalling. For instance, if I have the following:

    ConnectionManager()
    {
        listener = new TcpListener(port);
        listener.BeginAcceptSocket(new AsyncCallback(acceptConnection), listener);
    }

    public void acceptConnection(IAsyncResult ar)
    {
        //Do stuff
    }

does this mean that as soon as it finds a connection, it executes the "acceptConnection" function but then continues to execute through the caller function? (in this case going out of scope). How does this allow me to create a server application that will be able to take multiple clients? I am fairly new to this concept even though I have worked with threads before to manage server/client interaction. If I am being a little vague, please let me know. I have looked up multiple examples on MSDN and am still a little confused. Thank you ahead of time!

Upvotes: 2

Views: 1282

Answers (2)

Soonts
Soonts

Reputation: 21926

as soon as it finds a connection, it executes the "acceptConnection" function

Yes

then continues to execute through the caller function?

No.

what does the Async approach achieve

When done right, it allows processing much higher number of requests/second using fewer resources.

Imagine you're creating a server that should accept connections on 10 TCP ports.

With blocking API, you’ll have to create 10 threads just for accepting sockets. Threads are expensive system resource, e.g. every thread has its own stack, and switching between threads takes considerable time. If a client connecting to some socket, the OS will have to wake up the corresponding thread.

With async API, you post 10 asynchronous requests. When client is connecting, your acceptConnection method will be called by a thread from the CLR thread pool.

And one more thing.

If you want to continue executing the caller function after waiting for asynchronous I/O operation to complete, you should consider new C#’s async/await syntax, it allows you to do just that. The feature is available as a stand-alone library “Async CTP” for visual studio 2010, and included in visual studio 2012.

Upvotes: 3

andrew
andrew

Reputation: 1244

I don't profess to be a c# or sockets guru but from what I understand the code you've got above will accept the first connection and then no more. You would need to establish another BeginAccept.

Something like:

TcpListener listener = null;

ConnectionManager()
{
    listener = new TcpListener(port);
    listener.BeginAcceptSocket(new AsyncCallback(acceptConnection), listener);
}

public void acceptConnection(IAsyncResult ar)
{
    // Create async receive data code..

    // Get ready for a new connection
    listener.BeginAcceptSocket(new AsyncCallback(acceptConnection), listener);

}

So by using Async receive data in addition to the async connection, the accept connection finishes pretty quickly and sets up listening for a new connection. I guess you could re-order this too.

For straight socket connection (not TcpListener) this is what i used:

(connectedClient is a my own class which handles the receive & transmit functions and holds other info about the connection).

int Port = 7777; // or whatever port you want to listen on
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);
listenSocket = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);

listenSocket.Bind(ipLocal);

// create the call back for any client connections...
        listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);

private void OnClientConnection(IAsyncResult asyn)
    {
        if (socketClosed)
        {
            return;
        }

        try
        {
            Socket clientSocket = listenSocket.EndAccept(asyn);

            ConnectedClient connectedClient = new ConnectedClient(clientSocket, this);

            connectedClient.MessageReceived += OnMessageReceived;
            connectedClient.Disconnected += OnDisconnection;
            connectedClient.MessageSent += OnMessageSent;

            connectedClient.StartListening();

            // create the call back for any client connections...
            listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);

        }
        catch (ObjectDisposedException excpt)
        {
            // Deal with this, your code goes here

        }
        catch (Exception excpt)
        {
            // Deal with this, your code goes here
        }

    }

I hope this has answered what you're looking for ?

Upvotes: 2

Related Questions