SocketAsyncStatistics Class
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.