SocketAsyncEventArgs Clase

Definición

Representa una operación de socket asincrónico.

public ref class SocketAsyncEventArgs : EventArgs, IDisposable
public class SocketAsyncEventArgs : EventArgs, IDisposable
type SocketAsyncEventArgs = class
    inherit EventArgs
    interface IDisposable
Public Class SocketAsyncEventArgs
Inherits EventArgs
Implements IDisposable
Herencia
SocketAsyncEventArgs
Implementaciones

Ejemplos

En el ejemplo de código siguiente se implementa la lógica de conexión para el servidor de sockets que usa la SocketAsyncEventArgs clase . Después de aceptar una conexión, todos los datos leídos del cliente se devuelven al cliente. La lectura y el eco vuelven al patrón de cliente se continúan hasta que el cliente se desconecta. La clase BufferManager que usa este ejemplo se muestra en el ejemplo de código del SetBuffer(Byte[], Int32, Int32) método . La clase SocketAsyncEventArgsPool que se usa en este ejemplo se muestra en el ejemplo de código para el SocketAsyncEventArgs constructor.

// Implements the connection logic for the socket server.
// After accepting a connection, all data read from the client
// is sent back to the client. The read and echo back to the client pattern
// is continued until the client disconnects.
class Server
{
    private int m_numConnections;   // the maximum number of connections the sample is designed to handle simultaneously
    private int m_receiveBufferSize;// buffer size to use for each socket I/O operation
    BufferManager m_bufferManager;  // represents a large reusable set of buffers for all socket operations
    const int opsToPreAlloc = 2;    // read, write (don't alloc buffer space for accepts)
    Socket listenSocket;            // the socket used to listen for incoming connection requests
    // pool of reusable SocketAsyncEventArgs objects for write, read and accept socket operations
    SocketAsyncEventArgsPool m_readWritePool;
    int m_totalBytesRead;           // counter of the total # bytes received by the server
    int m_numConnectedSockets;      // the total number of clients connected to the server
    Semaphore m_maxNumberAcceptedClients;

    // Create an uninitialized server instance.
    // To start the server listening for connection requests
    // call the Init method followed by Start method
    //
    // <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously</param>
    // <param name="receiveBufferSize">buffer size to use for each socket I/O operation</param>
    public Server(int numConnections, int receiveBufferSize)
    {
        m_totalBytesRead = 0;
        m_numConnectedSockets = 0;
        m_numConnections = numConnections;
        m_receiveBufferSize = receiveBufferSize;
        // allocate buffers such that the maximum number of sockets can have one outstanding read and
        //write posted to the socket simultaneously
        m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc,
            receiveBufferSize);

        m_readWritePool = new SocketAsyncEventArgsPool(numConnections);
        m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections);
    }

    // Initializes the server by preallocating reusable buffers and
    // context objects.  These objects do not need to be preallocated
    // or reused, but it is done this way to illustrate how the API can
    // easily be used to create reusable objects to increase server performance.
    //
    public void Init()
    {
        // Allocates one large byte buffer which all I/O operations use a piece of.  This gaurds
        // against memory fragmentation
        m_bufferManager.InitBuffer();

        // preallocate pool of SocketAsyncEventArgs objects
        SocketAsyncEventArgs readWriteEventArg;

        for (int i = 0; i < m_numConnections; i++)
        {
            //Pre-allocate a set of reusable SocketAsyncEventArgs
            readWriteEventArg = new SocketAsyncEventArgs();
            readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
            readWriteEventArg.UserToken = new AsyncUserToken();

            // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
            m_bufferManager.SetBuffer(readWriteEventArg);

            // add SocketAsyncEventArg to the pool
            m_readWritePool.Push(readWriteEventArg);
        }
    }

    // Starts the server such that it is listening for
    // incoming connection requests.
    //
    // <param name="localEndPoint">The endpoint which the server will listening
    // for connection requests on</param>
    public void Start(IPEndPoint localEndPoint)
    {
        // create the socket which listens for incoming connections
        listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        listenSocket.Bind(localEndPoint);
        // start the server with a listen backlog of 100 connections
        listenSocket.Listen(100);

        // post accepts on the listening socket
        SocketAsyncEventArgs acceptEventArg = new SocketAsyncEventArgs();
        acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
        StartAccept(acceptEventArg);

        //Console.WriteLine("{0} connected sockets with one outstanding receive posted to each....press any key", m_outstandingReadCount);
        Console.WriteLine("Press any key to terminate the server process....");
        Console.ReadKey();
    }

    // Begins an operation to accept a connection request from the client
    //
    // <param name="acceptEventArg">The context object to use when issuing
    // the accept operation on the server's listening socket</param>
    public void StartAccept(SocketAsyncEventArgs acceptEventArg)
    {
        // loop while the method completes synchronously
        bool willRaiseEvent = false;
        while (!willRaiseEvent)
        {
            m_maxNumberAcceptedClients.WaitOne();

            // socket must be cleared since the context object is being reused
            acceptEventArg.AcceptSocket = null;            
            willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);
            if (!willRaiseEvent)
            {
                ProcessAccept(acceptEventArg);
            }
        }
    }

    // This method is the callback method associated with Socket.AcceptAsync
    // operations and is invoked when an accept operation is complete
    //
    void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
    {
        ProcessAccept(e);
        
        // Accept the next connection request
        StartAccept(e);
    }

    private void ProcessAccept(SocketAsyncEventArgs e)
    {
        Interlocked.Increment(ref m_numConnectedSockets);
        Console.WriteLine("Client connection accepted. There are {0} clients connected to the server",
            m_numConnectedSockets);

        // Get the socket for the accepted client connection and put it into the
        //ReadEventArg object user token
        SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop();
        ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket;

        // As soon as the client is connected, post a receive to the connection
        bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
        if (!willRaiseEvent)
        {
            ProcessReceive(readEventArgs);
        }
    }

    // This method is called whenever a receive or send operation is completed on a socket
    //
    // <param name="e">SocketAsyncEventArg associated with the completed receive operation</param>
    void IO_Completed(object sender, SocketAsyncEventArgs e)
    {
        // determine which type of operation just completed and call the associated handler
        switch (e.LastOperation)
        {
            case SocketAsyncOperation.Receive:
                ProcessReceive(e);
                break;
            case SocketAsyncOperation.Send:
                ProcessSend(e);
                break;
            default:
                throw new ArgumentException("The last operation completed on the socket was not a receive or send");
        }
    }

    // This method is invoked when an asynchronous receive operation completes.
    // If the remote host closed the connection, then the socket is closed.
    // If data was received then the data is echoed back to the client.
    //
    private void ProcessReceive(SocketAsyncEventArgs e)
    {
        // check if the remote host closed the connection
        AsyncUserToken token = (AsyncUserToken)e.UserToken;
        if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
        {
            //increment the count of the total bytes receive by the server
            Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred);
            Console.WriteLine("The server has read a total of {0} bytes", m_totalBytesRead);

            //echo the data received back to the client
            e.SetBuffer(e.Offset, e.BytesTransferred);
            bool willRaiseEvent = token.Socket.SendAsync(e);
            if (!willRaiseEvent)
            {
                ProcessSend(e);
            }
        }
        else
        {
            CloseClientSocket(e);
        }
    }

    // This method is invoked when an asynchronous send operation completes.
    // The method issues another receive on the socket to read any additional
    // data sent from the client
    //
    // <param name="e"></param>
    private void ProcessSend(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            // done echoing data back to the client
            AsyncUserToken token = (AsyncUserToken)e.UserToken;
            // read the next block of data send from the client
            bool willRaiseEvent = token.Socket.ReceiveAsync(e);
            if (!willRaiseEvent)
            {
                ProcessReceive(e);
            }
        }
        else
        {
            CloseClientSocket(e);
        }
    }

    private void CloseClientSocket(SocketAsyncEventArgs e)
    {
        AsyncUserToken token = e.UserToken as AsyncUserToken;

        // close the socket associated with the client
        try
        {
            token.Socket.Shutdown(SocketShutdown.Send);
        }
        // throws if client process has already closed
        catch (Exception) { }
        token.Socket.Close();

        // decrement the counter keeping track of the total number of clients connected to the server
        Interlocked.Decrement(ref m_numConnectedSockets);

        // Free the SocketAsyncEventArg so they can be reused by another client
        m_readWritePool.Push(e);

        m_maxNumberAcceptedClients.Release();
        Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets);
    }
}

Comentarios

La SocketAsyncEventArgs clase forma parte de un conjunto de mejoras en la System.Net.Sockets.Socket clase que proporcionan un patrón asincrónico alternativo que las aplicaciones de socket especializadas de alto rendimiento pueden usar. Esta clase se diseñó específicamente para aplicaciones de servidor de red que requieren un alto rendimiento. Una aplicación puede usar el patrón asincrónico mejorado exclusivamente o solo en áreas activas de destino (por ejemplo, al recibir grandes cantidades de datos).

La característica principal de estas mejoras es la elusión de la asignación y la sincronización repetidas de objetos durante la E/S de socket asincrónico de gran volumen. El patrón de diseño Begin/End implementado actualmente por la System.Net.Sockets.Socket clase requiere que se asigne un System.IAsyncResult objeto para cada operación de socket asincrónico.

En las nuevas System.Net.Sockets.Socket mejoras de clase, las operaciones de socket asincrónico se describen mediante objetos reutilizables SocketAsyncEventArgs asignados y mantenidos por la aplicación. Las aplicaciones de socket de alto rendimiento saben mejor la cantidad de operaciones de socket superpuestas que se deben mantener. La aplicación puede crear tantos objetos SocketAsyncEventArgs como necesite. Por ejemplo, si una aplicación de servidor necesita tener 15 operaciones de aceptación de socket pendientes en todo momento para admitir las tarifas de conexión de cliente entrantes, puede asignar 15 objetos reutilizables SocketAsyncEventArgs para ese fin.

El patrón para realizar una operación de socket asincrónico con esta clase consta de los pasos siguientes:

  1. Asigne un nuevo objeto de contexto SocketAsyncEventArgs u obtenga uno libre de un grupo de aplicaciones.

  2. Establezca las propiedades del objeto de contexto en la operación a punto de realizarse (el método de devolución de llamada de finalización, el búfer de datos, el desplazamiento en el búfer y la cantidad máxima de datos que se van a transferir, por ejemplo).

  3. Llame al método de socket adecuado (xxxAsync) para iniciar la operación asincrónica.

  4. Si el método de socket asincrónico (xxxAsync) devuelve true, en la devolución de llamada, consulte las propiedades de contexto para el estado de finalización.

  5. Si el método de socket asincrónico (xxxAsync) devuelve false, la operación se completó sincrónicamente. Para ver el resultado de la operación se pueden consultar las propiedades de contexto.

  6. Vuelva a usar el contexto para otra operación, vuelva a colocarlo en el grupo o descártelo.

La duración del nuevo objeto de contexto de operación de socket asincrónico viene determinado por referencias por el código de aplicación y las referencias de E/S asincrónicas. No es necesario que la aplicación conserve una referencia a un objeto de contexto de operación de socket asincrónico una vez que se ha enviado como parámetro a uno de los métodos de operación de socket asincrónico. La referencia se conserva hasta que se devuelve la devolución de llamada de finalización. Sin embargo, es ventajoso que la aplicación conserve la referencia al contexto para que se pueda reutilizar para una futura operación de socket asincrónico.

Constructores

SocketAsyncEventArgs()

Crea una instancia SocketAsyncEventArgs vacía.

SocketAsyncEventArgs(Boolean)

Inicializa el SocketAsyncEventArgs.

Propiedades

AcceptSocket

Obtiene o establece el socket que se va a usar o el socket creado para aceptar una conexión con un método de socket asincrónico.

Buffer

Obtiene el búfer de datos que se va a usar con un método de socket asincrónico.

BufferList

Obtiene o establece una matriz de búferes de datos que se va a usar con un método de socket asincrónico.

BytesTransferred

Obtiene el número de bytes transferidos en la operación de socket.

ConnectByNameError

Obtiene la excepción en el caso de un error de conexión cuando se usó DnsEndPoint.

ConnectSocket

Objeto Socket que se ha creado y conectado después de finalizar correctamente el método ConnectAsync.

Count

Obtiene la cantidad máxima de datos, en bytes, que se van a enviar o recibir en una operación asincrónica.

DisconnectReuseSocket

Obtiene o establece un valor que especifica si el socket se puede reutilizar después una operación de desconexión.

LastOperation

Obtiene el tipo de operación de socket más reciente realizada con este objeto de contexto.

MemoryBuffer

Obtiene la región de memoria que se va a usar como búfer con un método de socket asincrónico.

Offset

Obtiene el desplazamiento, en bytes, en el búfer de datos al que hace referencia la propiedad Buffer.

ReceiveMessageFromPacketInfo

Obtiene la dirección IP e interfaz de un paquete recibido.

RemoteEndPoint

Obtiene o establece el extremo IP remoto de una operación asincrónica.

SendPacketsElements

Obtiene o establece una matriz de búferes que se va a enviar para una operación asincrónica utilizada por el método SendPacketsAsync(SocketAsyncEventArgs).

SendPacketsFlags

Obtiene o establece una combinación bit a bit de valores TransmitFileOptions para una operación asincrónica utilizada por el método SendPacketsAsync(SocketAsyncEventArgs).

SendPacketsSendSize

Obtiene o establece el tamaño, en bytes, del bloque de datos utilizado en la operación de envío.

SocketClientAccessPolicyProtocol
Obsoleto.

Obtiene o establece el protocolo que se utiliza para descargar el archivo de directivas de acceso de cliente de socket.

SocketError

Obtiene o establece el resultado de la operación de socket asincrónico.

SocketFlags

Obtiene los resultados de una operación de socket asincrónico o establece el comportamiento de una operación asincrónica.

UserToken

Obtiene o establece a un objeto de usuario o de aplicación asociado a esta operación de socket asincrónico.

Métodos

Dispose()

Libera los recursos no administrados utilizados por la instancia de SocketAsyncEventArgs y, de forma opcional, elimina los recursos administrados.

Equals(Object)

Determina si el objeto especificado es igual que el objeto actual.

(Heredado de Object)
Finalize()

Libera los recursos que usa la clase SocketAsyncEventArgs.

GetHashCode()

Sirve como la función hash predeterminada.

(Heredado de Object)
GetType()

Obtiene el Type de la instancia actual.

(Heredado de Object)
MemberwiseClone()

Crea una copia superficial del Object actual.

(Heredado de Object)
OnCompleted(SocketAsyncEventArgs)

Representa un método al que se llama cuando se completa una operación asincrónica.

SetBuffer(Byte[], Int32, Int32)

Establece el búfer de datos que se va a usar con un método de socket asincrónico.

SetBuffer(Int32, Int32)

Establece el búfer de datos que se va a usar con un método de socket asincrónico.

SetBuffer(Memory<Byte>)

Establece la región de memoria que se va a usar como búfer con un método de socket asincrónico.

ToString()

Devuelve una cadena que representa el objeto actual.

(Heredado de Object)

Eventos

Completed

Evento utilizado para completar una operación asincrónica.

Se aplica a

Consulte también