SocketAsyncStatistics Class

Namespace: System.Net.Sockets
Assembly: System.Net.Primitives.dll

Provides statistics about asynchronous operations performed on a Socket.

Syntax

C#

public class SocketAsyncStatistics

Properties

CompletedSynchronously

Gets a value indicating whether the asynchronous operation completed synchronously.

public bool CompletedSynchronously { get; }

SocketError

Gets the SocketError returned by the asynchronous operation.

public SocketError SocketError { get; }

BytesTransferred

Gets the number of bytes transferred during the asynchronous operation.

public int BytesTransferred { get; }

Remarks

The SocketAsyncStatistics class is used to provide information about the completion of asynchronous socket operations. When an asynchronous socket method completes, the event handler receives an SocketAsyncEventArgs object, which contains a SocketAsyncStatistics property. This property can be used to inspect the outcome of the operation, such as whether it completed synchronously, any errors that occurred, and the number of bytes transferred.

Understanding these statistics is crucial for diagnosing issues with network applications and optimizing their performance. For example, if an operation consistently completes synchronously, it might indicate a bottleneck that could be addressed by improving buffer management or system resources.

Methods

Reset()

Resets the statistics to their initial state.

public void Reset()

This method can be useful for reusing a SocketAsyncEventArgs object for multiple operations without creating new objects, thereby reducing garbage collection overhead.

Example

C# Usage Example

using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; public class SocketAsyncExample { private static Socket _clientSocket; private static SocketAsyncEventArgs _connectArgs; private static SocketAsyncEventArgs _sendArgs; private static SocketAsyncEventArgs _receiveArgs; public static void Connect(string host, int port) { _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); var endpoint = new IPEndPoint(IPAddress.Parse(host), port); _connectArgs = new SocketAsyncEventArgs(); _connectArgs.RemoteEndPoint = endpoint; _connectArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ConnectCompleted); bool willRaiseEvent = _clientSocket.ConnectAsync(_connectArgs); if (!willRaiseEvent) { ConnectCompleted(null, _connectArgs); } } private static void ConnectCompleted(object sender, SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { Console.WriteLine($"Successfully connected to {e.RemoteEndPoint}"); // Prepare for receiving data _receiveArgs = new SocketAsyncEventArgs(); _receiveArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ReceiveCompleted); _receiveArgs.SetBuffer(new byte[1024], 0, 1024); // Allocate buffer for receiving bool willRaiseEvent = _clientSocket.ReceiveAsync(_receiveArgs); if (!willRaiseEvent) { ReceiveCompleted(null, _receiveArgs); } } else { Console.WriteLine($"Connection failed: {e.SocketError}"); // Handle connection error } } private static void ReceiveCompleted(object sender, SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success && e.BytesTransferred > 0) { // Process received data string receivedData = Encoding.ASCII.GetString(e.Buffer, e.Offset, e.BytesTransferred); Console.WriteLine($"Received: {receivedData}"); // Prepare to send data back string response = "Hello from server!"; _sendArgs = new SocketAsyncEventArgs(); _sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(SendCompleted); byte[] dataToSend = Encoding.ASCII.GetBytes(response); _sendArgs.SetBuffer(dataToSend, 0, dataToSend.Length); bool willRaiseEvent = _clientSocket.SendAsync(_sendArgs); if (!willRaiseEvent) { SendCompleted(null, _sendArgs); } } else if (e.BytesTransferred == 0) { Console.WriteLine("Connection closed by remote host."); // Handle connection closed } else { Console.WriteLine($"Receive error: {e.SocketError}"); // Handle receive error } } private static void SendCompleted(object sender, SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { Console.WriteLine($"Successfully sent {e.BytesTransferred} bytes."); // After sending, prepare to receive again for continuous communication _receiveArgs.SetBuffer(new byte[1024], 0, 1024); // Reset buffer for next receive bool willRaiseEvent = _clientSocket.ReceiveAsync(_receiveArgs); if (!willRaiseEvent) { ReceiveCompleted(null, _receiveArgs); } } else { Console.WriteLine($"Send error: {e.SocketError}"); // Handle send error } // Accessing SocketAsyncStatistics if (e.UserToken is SocketAsyncStatistics stats) { Console.WriteLine($"--- Send Operation Stats ---"); Console.WriteLine($" Completed Synchronously: {stats.CompletedSynchronously}"); Console.WriteLine($" Socket Error: {stats.SocketError}"); Console.WriteLine($" Bytes Transferred: {stats.BytesTransferred}"); Console.WriteLine($"----------------------------"); } } public static void Main(string[] args) { // Example: Connect to a dummy server (replace with a real server address if needed) // For demonstration, assume this is run in an environment where a server is listening. // In a real scenario, you'd need a corresponding server to connect to. Console.WriteLine("Attempting to connect..."); // Replace with a valid IP and port for testing // Example: Connect("127.0.0.1", 12345); // For simplicity in this example, we won't actually connect without a running server. // You would uncomment the line above and ensure a server is running. // To test the statistics directly, you can manually create and inspect them: Console.WriteLine("\nDemonstrating SocketAsyncStatistics:"); var dummyStats = new SocketAsyncEventArgs(); // A dummy event args // In a real async operation, the system would populate this. // Here, we simulate some values for demonstration. dummyStats.SocketError = SocketError.Success; // Accessing the statistics property might require a bit more setup or // a scenario where it's actually populated. // The 'e' parameter in 'Completed' events will have the relevant stats. // Let's simulate a completed event to show accessing stats. var simulatedSendArgs = new SocketAsyncEventArgs(); simulatedSendArgs.SocketError = SocketError.ConnectionReset; simulatedSendArgs.BytesTransferred = 0; // In a real scenario, the SDK might attach these stats. // For demonstration, imagine we could set them like this (this is illustrative): // simulatedSendArgs.SetUserToken(new SocketAsyncStatistics { CompletedSynchronously = false, SocketError = simulatedSendArgs.SocketError, BytesTransferred = simulatedSendArgs.BytesTransferred }); // Since we can't directly create and assign SocketAsyncStatistics this way for a demonstration, // we'll focus on how it's *accessed* when an operation completes. Console.WriteLine("Refer to the 'SendCompleted' method for how to access SocketAsyncStatistics."); // Keep console open Console.WriteLine("\nPress Enter to exit."); Console.ReadLine(); } }

This example demonstrates how to use asynchronous socket operations in .NET. The SocketAsyncStatistics are accessed within the SendCompleted event handler through the e.UserToken property, assuming it was populated with an instance of SocketAsyncStatistics during the operation's initiation. In practice, the framework manages the population of these statistics for you when you use the asynchronous socket methods.