SocketAsyncResult Class

System.Net.Sockets

Represents the result of an asynchronous socket operation.

Overview

The SocketAsyncResult class is used to manage the state and results of asynchronous socket operations, such as sending, receiving, connecting, and accepting connections. It implements the IAsyncResult interface, allowing for a consistent pattern for asynchronous programming in .NET.

When you initiate an asynchronous socket operation using methods like Socket.BeginSend, Socket.BeginReceive, or Socket.BeginAccept, a SocketAsyncResult object is created and returned. This object holds information about the operation's progress, including whether it has completed, if it completed synchronously, and provides access to the results upon completion.

Class Members

Properties

Name Description
AsyncState Gets the state object that was passed to the asynchronous operation.
CompletedSynchronously Gets a value indicating whether the asynchronous operation completed synchronously.
IsCompleted Gets a value indicating whether the asynchronous operation has completed.
AsyncWaitHandle Gets a handle that can be used to wait for the asynchronous operation to complete.
BytesTransferred Gets the number of bytes transferred during the asynchronous operation.
SocketError Gets the results of the asynchronous socket operation.

Methods

Name Description
Dispose() Releases the unmanaged resources used by the SocketAsyncResult and optionally releases the managed resources.
Reset() Resets the AsyncWaitHandle to the non-signaled state.

Example Usage

The following example demonstrates how to use SocketAsyncResult to perform an asynchronous receive operation.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class AsyncSocketExample
{
    private const int Port = 11000;
    private const int BufferSize = 1024;
    private Socket listener;

    public void StartServer()
    {
        try
        {
            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, Port);
            listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            listener.Bind(localEndPoint);
            listener.Listen(10);

            Console.WriteLine("Waiting for a connection...");
            // Start asynchronous accept operation
            listener.BeginAccept(new AsyncCallback(AcceptCallback), null);

            // Keep the server running to allow connections
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
        finally
        {
            listener?.Close();
        }
    }

    private void AcceptCallback(IAsyncResult asyncResult)
    {
        if (listener == null) return;

        Console.WriteLine("Connection accepted.");
        Socket clientSocket = listener.EndAccept(asyncResult);

        // Start the next accept operation to handle multiple clients
        listener.BeginAccept(new AsyncCallback(AcceptCallback), null);

        // Start asynchronous receive operation
        SocketAsyncState state = new SocketAsyncState { ClientSocket = clientSocket };
        clientSocket.BeginReceive(state.Buffer, 0, BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
    }

    private void ReceiveCallback(IAsyncResult asyncResult)
    {
        SocketAsyncState state = (SocketAsyncState)asyncResult.AsyncState;
        Socket clientSocket = state.ClientSocket;

        try
        {
            // Retrieve the SocketAsyncResult to access BytesTransferred and SocketError
            SocketAsyncResult socketAsyncResult = asyncResult as SocketAsyncResult;

            int bytesRead = clientSocket.EndReceive(asyncResult);

            if (bytesRead > 0)
            {
                string receivedData = Encoding.ASCII.GetString(state.Buffer, 0, bytesRead);
                Console.WriteLine($"Received: {receivedData}");

                // Access information from SocketAsyncResult
                Console.WriteLine($"Bytes Transferred (sync check): {socketAsyncResult.BytesTransferred}");
                Console.WriteLine($"Completed Synchronously: {socketAsyncResult.CompletedSynchronously}");
                Console.WriteLine($"Socket Error: {socketAsyncResult.SocketError}");

                // Echo back the received data
                byte[] sendBuffer = Encoding.ASCII.GetBytes("Echo: " + receivedData);
                clientSocket.BeginSend(sendBuffer, 0, sendBuffer.Length, SocketFlags.None, new AsyncCallback(SendCallback), clientSocket);

                // Start the next receive operation
                clientSocket.BeginReceive(state.Buffer, 0, BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
            }
            else
            {
                Console.WriteLine("Client disconnected.");
                clientSocket.Close();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine($"Error receiving data: {e.Message}");
            clientSocket.Close();
        }
    }

    private void SendCallback(IAsyncResult asyncResult)
    {
        Socket clientSocket = (Socket)asyncResult.AsyncState;
        try
        {
            clientSocket.EndSend(asyncResult);
            Console.WriteLine("Data echoed back.");
        }
        catch (Exception e)
        {
            Console.WriteLine($"Error sending data: {e.Message}");
            clientSocket.Close();
        }
    }

    // Helper class to hold state for asynchronous operations
    public class SocketAsyncState
    {
        public Socket ClientSocket { get; set; }
        public byte[] Buffer { get; } = new byte[BufferSize];
    }

    public static void Main(string[] args)
    {
        AsyncSocketExample server = new AsyncSocketExample();
        server.StartServer();
    }
}

Remarks

The SocketAsyncResult class is an internal implementation detail of the .NET asynchronous socket APIs. Developers typically interact with it indirectly through the IAsyncResult interface returned by the Begin... methods.

Key properties like BytesTransferred and SocketError provide essential details about the outcome of the asynchronous operation when it completes. The AsyncWaitHandle property is crucial for scenarios where you need to block and wait for an operation to finish, although using callbacks is generally preferred for true asynchronous behavior.

It's important to ensure that the IAsyncResult object is properly handled, especially when calling End... methods. These methods will retrieve the results of the operation and also throw any exceptions that occurred during its execution.