SocketAsyncEventArgs Klasa

Definicja

Reprezentuje operację asynchronicznego gniazda.

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
Dziedziczenie
SocketAsyncEventArgs
Implementuje

Przykłady

Poniższy przykład kodu implementuje logikę połączenia dla serwera gniazd, który używa SocketAsyncEventArgs klasy . Po zaakceptowaniu połączenia wszystkie dane odczytane z klienta są wysyłane z powrotem do klienta. Odczyt i echo z powrotem do wzorca klienta są kontynuowane do momentu rozłączenia klienta. Klasa BufferManager używana przez ten przykład jest wyświetlana w przykładzie SetBuffer(Byte[], Int32, Int32) kodu dla metody . Klasa SocketAsyncEventArgsPool używana w tym przykładzie jest wyświetlana w przykładzie kodu konstruktora 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);
            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);
    }
}

Uwagi

Klasa SocketAsyncEventArgs jest częścią zestawu ulepszeń System.Net.Sockets.Socket klasy, które zapewniają alternatywny wzorzec asynchroniczny, który może być używany przez wyspecjalizowane aplikacje gniazd o wysokiej wydajności. Ta klasa została specjalnie zaprojektowana dla aplikacji serwera sieciowego, które wymagają wysokiej wydajności. Aplikacja może używać rozszerzonego wzorca asynchronicznego wyłącznie lub tylko w docelowych obszarach gorących (na przykład podczas odbierania dużych ilości danych).

Główną cechą tych ulepszeń jest unikanie powtarzającej się alokacji i synchronizacji obiektów podczas operacji we/wy gniazda asynchronicznego o dużej ilości. Wzorzec projektu Początek/Koniec, który jest obecnie implementowany przez System.Net.Sockets.Socket klasę System.IAsyncResult , wymaga przydzieleniu obiektu dla każdej operacji asynchronicznego gniazda.

W nowych System.Net.Sockets.Socket ulepszeniach klasy operacje asynchronicznego gniazda są opisywane przez obiekty wielokrotnego użytku SocketAsyncEventArgs przydzielone i obsługiwane przez aplikację. Aplikacje gniazd o wysokiej wydajności najlepiej znają ilość nakładających się operacji gniazd, które muszą być trwałe. Aplikacja może utworzyć dowolną liczbę SocketAsyncEventArgs obiektów, których potrzebuje. Jeśli na przykład aplikacja serwera musi mieć 15 gniazd akceptowanych operacji zaległych przez cały czas w celu obsługi przychodzących stawek połączeń klienta, może przydzielić do tego celu 15 obiektów wielokrotnego użytku SocketAsyncEventArgs .

Wzorzec wykonywania operacji asynchronicznego gniazda z tą klasą składa się z następujących kroków:

  1. Przydziel nowy SocketAsyncEventArgs obiekt kontekstu lub uzyskaj bezpłatny obiekt z puli aplikacji.

  2. Ustaw właściwości obiektu kontekstu na operację, która ma zostać wykonana (metoda wywołania zwrotnego ukończenia, bufor danych, przesunięcie do buforu i maksymalna ilość danych do transferu, na przykład).

  3. Wywołaj odpowiednią metodę gniazda (xxxAsync), aby zainicjować operację asynchroniczną.

  4. Jeśli metoda asynchronicznego gniazda (xxxAsync) zwraca wartość true, w wywołaniu zwrotnym wykonaj zapytanie o właściwości kontekstu pod kątem stanu ukończenia.

  5. Jeśli metoda asynchronicznego gniazda (xxxAsync) zwraca wartość false, operacja została ukończona synchronicznie. Właściwości kontekstu mogą być odpytywane dla wyniku operacji.

  6. Ponownie użyj kontekstu dla innej operacji, umieść go z powrotem w puli lub odrzuć.

Okres istnienia nowego obiektu kontekstu operacji asynchronicznego gniazda zależy od odwołań do kodu aplikacji i asynchronicznych odwołań we/wy. Nie jest konieczne, aby aplikacja zachowała odwołanie do obiektu kontekstu operacji asynchronicznego gniazda po przesłaniu go jako parametru do jednej z metod operacji asynchronicznego gniazda. Pozostanie on przywołyny do momentu powrotu wywołania zwrotnego ukończenia. Jednak korzystne jest, aby aplikacja zachowała odwołanie do kontekstu, aby można było go ponownie użyć do przyszłej operacji asynchronicznego gniazda.

Konstruktory

SocketAsyncEventArgs()

Tworzy puste SocketAsyncEventArgs wystąpienie.

SocketAsyncEventArgs(Boolean)

Inicjuje element SocketAsyncEventArgs.

Właściwości

AcceptSocket

Pobiera lub ustawia gniazdo do użycia lub gniazdo utworzone do akceptowania połączenia z metodą asynchronicznego gniazda.

Buffer

Pobiera bufor danych do użycia z metodą asynchronicznego gniazda.

BufferList

Pobiera lub ustawia tablicę buforów danych do użycia z metodą asynchronicznego gniazda.

BytesTransferred

Pobiera liczbę bajtów przesyłanych w operacji gniazda.

ConnectByNameError

Pobiera wyjątek w przypadku awarii połączenia, gdy DnsEndPoint był używany.

ConnectSocket

Utworzony i połączony Socket obiekt po pomyślnym zakończeniu ConnectAsync metody.

Count

Pobiera maksymalną ilość danych w bajtach do wysyłania lub odbierania w operacji asynchronicznej.

DisconnectReuseSocket

Pobiera lub ustawia wartość określającą, czy gniazdo może zostać ponownie użyte po operacji rozłączenia.

LastOperation

Pobiera typ operacji gniazda ostatnio wykonane z tym obiektem kontekstu.

MemoryBuffer

Pobiera region pamięci do użycia jako bufor z metodą asynchronicznego gniazda.

Offset

Pobiera przesunięcie (w bajtach) do bufora danych, do których odwołuje się Buffer właściwość .

ReceiveMessageFromPacketInfo

Pobiera adres IP i interfejs odebranego pakietu.

RemoteEndPoint

Pobiera lub ustawia zdalny punkt końcowy adresu IP dla operacji asynchronicznej.

SendPacketsElements

Pobiera lub ustawia tablicę buforów do wysłania dla operacji asynchronicznej używanej przez metodę SendPacketsAsync(SocketAsyncEventArgs) .

SendPacketsFlags

Pobiera lub ustawia bitową kombinację TransmitFileOptions wartości dla operacji asynchronicznej używanej przez metodę SendPacketsAsync(SocketAsyncEventArgs) .

SendPacketsSendSize

Pobiera lub ustawia rozmiar bloku danych używanego w operacji wysyłania w bajtach.

SocketClientAccessPolicyProtocol
Nieaktualne.

Pobiera lub ustawia protokół używany do pobierania pliku zasad dostępu klienta gniazda.

SocketError

Pobiera lub ustawia wynik operacji asynchronicznego gniazda.

SocketFlags

Pobiera wyniki operacji asynchronicznego gniazda lub ustawia zachowanie operacji asynchronicznej.

UserToken

Pobiera lub ustawia obiekt użytkownika lub aplikacji skojarzony z tą operacją asynchronicznego gniazda.

Metody

Dispose()

Zwalnia niezarządzane zasoby używane przez SocketAsyncEventArgs wystąpienie i opcjonalnie usuwa zasoby zarządzane.

Equals(Object)

Określa, czy dany obiekt jest taki sam, jak bieżący obiekt.

(Odziedziczone po Object)
Finalize()

Zwalnia zasoby używane przez klasę SocketAsyncEventArgs .

GetHashCode()

Służy jako domyślna funkcja skrótu.

(Odziedziczone po Object)
GetType()

Type Pobiera wartość bieżącego wystąpienia.

(Odziedziczone po Object)
MemberwiseClone()

Tworzy płytkią kopię bieżącego Objectelementu .

(Odziedziczone po Object)
OnCompleted(SocketAsyncEventArgs)

Reprezentuje metodę wywoływaną po zakończeniu operacji asynchronicznej.

SetBuffer(Byte[], Int32, Int32)

Ustawia bufor danych do użycia z metodą asynchronicznego gniazda.

SetBuffer(Int32, Int32)

Ustawia bufor danych do użycia z metodą asynchronicznego gniazda.

SetBuffer(Memory<Byte>)

Ustawia region pamięci, który ma być używany jako bufor z metodą asynchronicznego gniazda.

ToString()

Zwraca ciąg reprezentujący bieżący obiekt.

(Odziedziczone po Object)

Zdarzenia

Completed

Zdarzenie używane do ukończenia operacji asynchronicznej.

Dotyczy

Zobacz też