SocketAsyncEventArgs Classe

Definição

Representa uma operação de soquete assíncrono.

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
Herança
SocketAsyncEventArgs
Implementações

Exemplos

O exemplo de código a seguir implementa a lógica de conexão para o servidor de soquete que usa a SocketAsyncEventArgs classe. Depois de aceitar uma conexão, todos os dados lidos do cliente são enviados de volta para o cliente. A leitura e o eco de volta ao padrão do cliente são continuados até que o cliente se desconecte. A classe BufferManager usada por este exemplo é exibida no exemplo de código do SetBuffer(Byte[], Int32, Int32) método. A classe SocketAsyncEventArgsPool usada neste exemplo é exibida no exemplo de código do SocketAsyncEventArgs construtor.

// 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);
    }
}

Comentários

A SocketAsyncEventArgs classe faz parte de um conjunto de aprimoramentos para a System.Net.Sockets.Socket classe que fornecem um padrão assíncrono alternativo que pode ser usado por aplicativos especializados de soquete de alto desempenho. Essa classe foi projetada especificamente para aplicativos de servidor de rede que exigem alto desempenho. Um aplicativo pode usar o padrão assíncrono aprimorado exclusivamente ou somente em áreas quentes de destino (por exemplo, ao receber grandes quantidades de dados).

O principal recurso dessas melhorias é evitar a alocação e a sincronização repetidas de objetos durante a E/S de soquete assíncrono de alto volume. O padrão de design Begin/End atualmente implementado pela System.Net.Sockets.Socket classe requer que um System.IAsyncResult objeto seja alocado para cada operação de soquete assíncrona.

Nos novos System.Net.Sockets.Socket aprimoramentos de classe, as operações de soquete assíncronas são descritas por objetos reutilizáveis SocketAsyncEventArgs alocados e mantidos pelo aplicativo. Os aplicativos de soquete de alto desempenho sabem muito bem a quantidade de operações de soquete sobreposto que devem ser sustentadas. O aplicativo pode criar a quantidade de objetos SocketAsyncEventArgs de que precisar. Por exemplo, se um aplicativo de servidor precisar ter 15 operações de aceitação de soquete pendentes o tempo todo para dar suporte a taxas de conexão de cliente de entrada, ele poderá alocar 15 objetos reutilizáveis SocketAsyncEventArgs para essa finalidade.

O padrão para executar uma operação de soquete assíncrono com essa classe consiste nas seguintes etapas:

  1. Alocar um novo objeto de contexto SocketAsyncEventArgs ou obter um gratuito em um pool de aplicativos.

  2. Defina propriedades no objeto de contexto para a operação prestes a ser executada (o método de retorno de chamada de conclusão, o buffer de dados, o deslocamento para o buffer e a quantidade máxima de dados a serem transferidos, por exemplo).

  3. Chamar o método de soquete apropriado (xxxAsync) para iniciar a operação assíncrona.

  4. Se o método soquete assíncrono (xxxAsync) retornar true, no retorno de chamada, consulte as propriedades de contexto para o status de conclusão.

  5. Se o método soquete assíncrono (xxxAsync) retornar false, a operação será concluída de forma síncrona. As propriedades do contexto podem ser consultadas para obter o resultado da operação.

  6. Reutilizar o contexto para outra operação, colocá-lo novamente no pool ou descartá-lo.

O tempo de vida do novo objeto de contexto de operação de soquete assíncrono é determinado por referências pelo código do aplicativo e referências assíncronas de E/S. Não é necessário que o aplicativo retenha uma referência a um objeto de contexto da operação de soquete assíncrono depois que ele é enviado como um parâmetro para um dos métodos da operação de soquete assíncrono. Ele permanecerá referenciado até o retorno do retorno de chamada de conclusão. No entanto, é vantajoso para o aplicativo manter a referência ao contexto para que ele possa ser reutilizado para uma futura operação de soquete assíncrona.

Construtores

SocketAsyncEventArgs()

Cria uma instância SocketAsyncEventArgs vazia.

SocketAsyncEventArgs(Boolean)

Inicializa o SocketAsyncEventArgs.

Propriedades

AcceptSocket

Obtém ou define o soquete a ser usado ou o soquete criado para aceitar uma conexão com um método de soquete assíncrono.

Buffer

Obtém o buffer de dados a ser usado com um método de soquete assíncrono.

BufferList

Obtém ou define uma matriz de buffers de dados a ser usada com um método de soquete assíncrono.

BytesTransferred

Obtém o número de bytes transferidos na operação de soquete.

ConnectByNameError

Obtém a exceção no caso de falha de conexão quando um DnsEndPoint foi usado.

ConnectSocket

O objeto Socket criado e conectado após a conclusão bem-sucedida do método ConnectAsync.

Count

Obtém a quantidade máxima de dados, em bytes, a ser enviada ou recebida em uma operação assíncrona.

DisconnectReuseSocket

Obtém ou define um valor que especifica se o soquete poderá ser reutilizado após uma operação de desconexão.

LastOperation

Obtém o tipo de operação de soquete executada mais recentemente com esse objeto de contexto.

MemoryBuffer

Obtém a região de memória a ser usada como um buffer com um método de soquete assíncrono.

Offset

Obtém o deslocamento, em bytes, para o buffer de dados referenciado pela propriedade Buffer.

ReceiveMessageFromPacketInfo

Obtém o endereço IP e a interface de um pacote recebido.

RemoteEndPoint

Obtém ou define o ponto de extremidade IP remoto para uma operação assíncrona.

SendPacketsElements

Obtém ou define uma matriz de buffers a ser enviada para uma operação assíncrona usada pelo método SendPacketsAsync(SocketAsyncEventArgs).

SendPacketsFlags

Obtém ou define uma combinação bit a bit de valores TransmitFileOptions para uma operação assíncrona usada pelo método SendPacketsAsync(SocketAsyncEventArgs).

SendPacketsSendSize

Obtém ou define o tamanho, em bytes, do bloco de dados usado na operação de envio.

SocketClientAccessPolicyProtocol
Obsoleto.

Obtém ou define o protocolo a ser usado para baixar o arquivo de política de acesso de cliente do soquete.

SocketError

Obtém ou define o resultado da operação de soquete assíncrona.

SocketFlags

Obtém os resultados de uma operação de soquete assíncrona ou define o comportamento de uma operação assíncrona.

UserToken

Obtém ou define um objeto de usuário ou de aplicativo associado a essa operação de soquete assíncrona.

Métodos

Dispose()

Libera os recursos não gerenciados usados pela instância SocketAsyncEventArgs e, opcionalmente, descarta os recursos gerenciados.

Equals(Object)

Determina se o objeto especificado é igual ao objeto atual.

(Herdado de Object)
Finalize()

Libera os recursos usados pela classe SocketAsyncEventArgs.

GetHashCode()

Serve como a função de hash padrão.

(Herdado de Object)
GetType()

Obtém o Type da instância atual.

(Herdado de Object)
MemberwiseClone()

Cria uma cópia superficial do Object atual.

(Herdado de Object)
OnCompleted(SocketAsyncEventArgs)

Representa um método chamado quando uma operação assíncrona é concluída.

SetBuffer(Byte[], Int32, Int32)

Define o buffer de dados a ser usado com um método de soquete assíncrono.

SetBuffer(Int32, Int32)

Define o buffer de dados a ser usado com um método de soquete assíncrono.

SetBuffer(Memory<Byte>)

Define a região de memória a ser usada como um buffer com um método de soquete assíncrono.

ToString()

Retorna uma cadeia de caracteres que representa o objeto atual.

(Herdado de Object)

Eventos

Completed

O evento usado para concluir uma operação assíncrona.

Aplica-se a

Confira também