Поделиться через


SocketAsyncEventArgs Класс

Определение

Представляет асинхронную операцию сокета.

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
Наследование
SocketAsyncEventArgs
Реализации

Примеры

В следующем примере кода реализуется логика подключения для сервера сокета, использующего SocketAsyncEventArgs класс . После принятия подключения все данные, считанные из клиента, отправляются обратно клиенту. Чтение и обратная связь с шаблоном клиента продолжается до тех пор, пока клиент не отключится. Класс BufferManager, используемый в этом примере, отображается в примере кода для SetBuffer(Byte[], Int32, Int32) метода . Класс SocketAsyncEventArgsPool, используемый в этом примере, отображается в примере кода для конструктора SocketAsyncEventArgs .

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

            // 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();
        readEventArgs.UserToken = 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
        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);
            Socket socket = (Socket)e.UserToken;
            bool willRaiseEvent = 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
            Socket socket = (Socket)e.UserToken;
            // read the next block of data send from the client
            bool willRaiseEvent = socket.ReceiveAsync(e);
            if (!willRaiseEvent)
            {
                ProcessReceive(e);
            }
        }
        else
        {
            CloseClientSocket(e);
        }
    }

    private void CloseClientSocket(SocketAsyncEventArgs e)
    {
        Socket socket = (Socket)e.UserToken;

        // close the socket associated with the client
        try
        {
            socket.Shutdown(SocketShutdown.Send);
        }
        // throws if client process has already closed
        catch (Exception) { }
        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);
    }
}

Комментарии

Класс SocketAsyncEventArgs является частью набора усовершенствований System.Net.Sockets.Socket класса , которые предоставляют альтернативный асинхронный шаблон, который может использоваться специализированными высокопроизводительные сокетные приложения. Этот класс был специально разработан для приложений сетевого сервера, которым требуется высокая производительность. Приложение может использовать расширенный асинхронный шаблон исключительно или только в целевых горячих областях (например, при получении больших объемов данных).

Главное преимущество этих улучшений — устранение необходимости в повторном выделении и синхронизации объектов во время асинхронных операций ввода-вывода больших объемов данных на сокете. Шаблон проектирования Begin/End, реализованный классом , System.Net.Sockets.Socket требует выделения объекта для каждой System.IAsyncResult асинхронной операции сокета.

В новых System.Net.Sockets.Socket улучшениях класса асинхронные операции сокетов описываются многократно используемыми SocketAsyncEventArgs объектами, выделенными и поддерживаемыми приложением. Высокопроизводительному приложению сокета лучше всего известно, сколько перекрывающихся операций сокета необходимо поддерживать. Приложение может создать столько объектов SocketAsyncEventArgs, сколько ему требуется. Например, если серверное приложение должно иметь 15 невыполненных операций приема сокетов для поддержки скорости входящих подключений клиентов, оно может выделить 15 повторно используемых SocketAsyncEventArgs объектов для этой цели.

Шаблон выполнения асинхронной операции на сокете с помощью этого класса состоит из перечисленных ниже действий.

  1. Выделите новый объект контекста SocketAsyncEventArgs или получите свободный объект из пула приложений.

  2. Присвойте свойствам объекта контекста операцию, которую необходимо выполнить (например, метод обратного вызова завершения, буфер данных, смещение в буфер и максимальный объем передаваемых данных).

  3. Вызовите соответствующий метод сокета (xxxAsync), чтобы инициировать асинхронную операцию.

  4. Если асинхронный метод сокета (xxxAsync) возвращает значение true, в обратном вызове запросите свойства контекста для получения состояния завершения.

  5. Если асинхронный метод сокета (xxxAsync) возвращает значение false, операция выполняется синхронно. Результат операции можно запросить из свойств контекста.

  6. Используйте контекст повторно для другой операции, верните его в пул или удалите.

Время существования нового объекта контекста асинхронной операции сокета определяется ссылками кода приложения и асинхронными ссылками на операции ввода-вывода. Приложению не требуется сохранять ссылку на объект контекста асинхронной операции на сокете после ее передачи в качестве параметра в один из методов асинхронной операции на сокете. Ссылка сохраняется до тех пор, пока не будет возвращен обратный вызов завершения. Однако для приложения целесообразно сохранить ссылку на контекст, чтобы ее можно было повторно использовать для будущей асинхронной операции сокета.

Конструкторы

SocketAsyncEventArgs()

Создает пустой экземпляр SocketAsyncEventArgs.

SocketAsyncEventArgs(Boolean)

Инициализирует объект SocketAsyncEventArgs.

Свойства

AcceptSocket

Возвращает или задает сокет для применения или сокет, созданный для принятия запроса на подключения, с помощью асинхронного метода сокета.

Buffer

Получает буфер данных для применения в асинхронном методе сокета.

BufferList

Возвращает или задает массив буферов данных для применения в асинхронном методе сокета.

BytesTransferred

Получает количество байтов, переданных в операции сокета.

ConnectByNameError

Получает исключение в случае сбоя соединения при использовании DnsEndPoint.

ConnectSocket

Созданный и подключенный объект Socket после успешного выполнения метода ConnectAsync.

Count

Получает значение, равное максимальному количеству данных (в байтах), которое может быть отправлено или получено в асинхронной операции.

DisconnectReuseSocket

Возвращает или задает значение, указывающее, может ли сокет быть повторно использован после операции отключения.

LastOperation

Получает тип операции сокета, которая была выполнена последней с этим объектом контекста.

MemoryBuffer

Возвращает область памяти, используемую в качестве буфера с асинхронным методом сокета.

Offset

Получает смещение (в байтах) в буфере данных, на который ссылается свойство Buffer.

ReceiveMessageFromPacketInfo

Получает IP-адрес и интерфейс получаемого пакета.

RemoteEndPoint

Возвращает или задает удаленную конечную точка IP для асинхронной операции.

SendPacketsElements

Возвращает или задает массив буферов для отправки для асинхронной операции, используемой методом SendPacketsAsync(SocketAsyncEventArgs).

SendPacketsFlags

Возвращает или задает битовую комбинацию значений TransmitFileOptions для асинхронной операции, используемой методом SendPacketsAsync(SocketAsyncEventArgs).

SendPacketsSendSize

Возвращает или задает размер (в байтах) блока данных, используемый в операции отправки.

SocketClientAccessPolicyProtocol
Устаревшие..

Получает или задает Протокол, используемый, чтобы загрузить файл политики доступа к сокету клиента.

SocketError

Возвращает или задает результат асинхронной операции сокета.

SocketFlags

Получает результат асинхронной операции сокета или задает поведение асинхронной операции.

UserToken

Возвращает или задает объект пользователя или приложения, связанный с данной асинхронной операцией сокета.

Методы

Dispose()

Освобождает неуправляемые ресурсы, используемые экземпляром класса SocketAsyncEventArgs, и при необходимости удаляет управляемые ресурсы.

Equals(Object)

Определяет, равен ли указанный объект текущему объекту.

(Унаследовано от Object)
Finalize()

Освобождает ресурсы, используемые классом SocketAsyncEventArgs.

GetHashCode()

Служит хэш-функцией по умолчанию.

(Унаследовано от Object)
GetType()

Возвращает объект Type для текущего экземпляра.

(Унаследовано от Object)
MemberwiseClone()

Создает неполную копию текущего объекта Object.

(Унаследовано от Object)
OnCompleted(SocketAsyncEventArgs)

Представляет метод, вызываемый после завершения асинхронной операции.

SetBuffer(Byte[], Int32, Int32)

Задает буфер данных для применения в асинхронном методе сокета.

SetBuffer(Int32, Int32)

Задает буфер данных для применения в асинхронном методе сокета.

SetBuffer(Memory<Byte>)

Задает область памяти, используемую в качестве буфера с асинхронным методом сокета.

ToString()

Возвращает строку, представляющую текущий объект.

(Унаследовано от Object)

События

Completed

Событие, используемое для завершения асинхронной операции.

Применяется к

См. также раздел