Sdílet prostřednictvím


SocketAsyncEventArgs Třída

Definice

Představuje asynchronní operaci soketu.

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
Dědičnost
SocketAsyncEventArgs
Implementuje

Příklady

Následující příklad kódu implementuje logiku připojení pro soketový server, který používá SocketAsyncEventArgs třídu . Po přijetí připojení se všechna data načtená z klienta odešlou zpět klientovi. Čtení a odezva zpět na vzor klienta pokračuje, dokud se klient neodpojí. Třída BufferManager, která se používá v tomto příkladu, je zobrazena v příkladu kódu pro metodu SetBuffer(Byte[], Int32, Int32) . SocketAsyncEventArgsPool Třída, která se používá v tomto příkladu, je zobrazena v příkladu kódu konstruktoru 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);
    }
}

Poznámky

Třída SocketAsyncEventArgs je součástí sady vylepšení System.Net.Sockets.Socket třídy, které poskytují alternativní asynchronní vzor, který může být použit specializovanými vysoce výkonnými aplikacemi soketů. Tato třída byla speciálně navržena pro síťové serverové aplikace, které vyžadují vysoký výkon. Aplikace může používat vylepšený asynchronní vzor výhradně nebo pouze v cílových horkých oblastech (například při příjmu velkých objemů dat).

Hlavním rysem těchto vylepšení je zabránění opakovanému přidělování a synchronizaci objektů během vstupně-výstupních operací asynchronních soketů s vysokým objemem. Vzor návrhu začátek/konec aktuálně implementovaný System.Net.Sockets.Socket třídou vyžaduje přidělení objektu System.IAsyncResult pro každou asynchronní operaci soketu.

V nových System.Net.Sockets.Socket vylepšeních tříd jsou asynchronní operace soketů popsány opakovaně použitelnými SocketAsyncEventArgs objekty přidělenými a udržovanými aplikací. Vysoce výkonné aplikace soketů nejlépe znají množství překrývajících se operací soketů, které je potřeba udržovat. Aplikace může vytvořit tolik SocketAsyncEventArgs objektů, které potřebuje. Pokud například serverová aplikace potřebuje mít vždy nevyřízených 15 operací přijetí soketů kvůli podpoře příchozích klientských připojení, může pro tento účel přidělit 15 opakovaně použitelných SocketAsyncEventArgs objektů.

Vzor pro provádění asynchronní operace soketu s touto třídou se skládá z následujících kroků:

  1. Přidělte nový SocketAsyncEventArgs objekt kontextu nebo získejte bezplatný objekt z fondu aplikací.

  2. Nastavte vlastnosti kontextového objektu na operaci, která se má provést (například metoda zpětného volání dokončení, datová vyrovnávací paměť, posun do vyrovnávací paměti a maximální množství dat, která se mají přenést).

  3. Voláním příslušné metody soketu (xxxAsync) zahájíte asynchronní operaci.

  4. Pokud metoda asynchronního soketu (xxxAsync) vrátí hodnotu true, zadejte ve zpětném volání dotaz na vlastnosti kontextu pro stav dokončení.

  5. Pokud metoda asynchronního soketu (xxxAsync) vrátí hodnotu false, operace se dokončila synchronně. Vlastnosti kontextu mohou být dotazovány pro výsledek operace.

  6. Znovu použijte kontext pro jinou operaci, vložte ho zpět do fondu nebo ho zahoďte.

Životnost nového objektu kontextu asynchronní operace soketu je určena odkazy kódem aplikace a asynchronními vstupně-výstupními odkazy. Není nutné, aby aplikace zachovala odkaz na objekt kontextu asynchronní operace soketu poté, co je odeslán jako parametr některé z metod asynchronní operace soketu. Zůstane odkazovaný, dokud se nevrátí zpětné volání dokončení. Je však pro aplikaci výhodné zachovat odkaz na kontext, aby ho bylo možné znovu použít pro budoucí asynchronní operaci soketu.

Konstruktory

SocketAsyncEventArgs()

Vytvoří prázdnou SocketAsyncEventArgs instanci.

SocketAsyncEventArgs(Boolean)

Inicializuje .SocketAsyncEventArgs

Vlastnosti

AcceptSocket

Získá nebo nastaví soket použít nebo soket vytvořený pro přijetí připojení s asynchronní soket metoda.

Buffer

Získá vyrovnávací paměť dat pro použití s asynchronní soket metoda.

BufferList

Získá nebo nastaví pole datových vyrovnávacích pamětí pro použití s asynchronní soket metoda.

BytesTransferred

Získá počet bajtů přenesených v operaci soketu.

ConnectByNameError

Získá výjimku v případě selhání připojení při DnsEndPoint použití.

ConnectSocket

Vytvořený a připojený Socket objekt po úspěšném dokončení ConnectAsync metody.

Count

Získá maximální množství dat v bajtech, které chcete odeslat nebo přijmout v asynchronní operaci.

DisconnectReuseSocket

Získá nebo nastaví hodnotu, která určuje, zda soket lze znovu použít po operaci odpojení.

LastOperation

Získá typ operace soketu naposledy provedených s tímto kontextovým objektem.

MemoryBuffer

Získá oblast paměti použít jako vyrovnávací paměť s asynchronní soket metoda.

Offset

Získá posun v bajtech do vyrovnávací paměti dat, na kterou Buffer odkazuje vlastnost.

ReceiveMessageFromPacketInfo

Získá IP adresu a rozhraní přijatého paketu.

RemoteEndPoint

Získá nebo nastaví vzdálený koncový bod IP pro asynchronní operaci.

SendPacketsElements

Získá nebo nastaví pole vyrovnávacích pamětí, které mají být odeslány pro asynchronní operace používané metodou SendPacketsAsync(SocketAsyncEventArgs) .

SendPacketsFlags

Získá nebo nastaví bitové kombinace TransmitFileOptions hodnot pro asynchronní operace používané metodou SendPacketsAsync(SocketAsyncEventArgs) .

SendPacketsSendSize

Získá nebo nastaví velikost v bajtech datového bloku použitého v operaci odeslání.

SocketClientAccessPolicyProtocol
Zastaralé.

Získá nebo nastaví protokol, který se má použít ke stažení souboru zásad přístupu klienta soketu.

SocketError

Získá nebo nastaví výsledek operace asynchronního soketu.

SocketFlags

Získá výsledky asynchronní operace soketu nebo nastaví chování asynchronní operace.

UserToken

Získá nebo nastaví uživatele nebo objekt aplikace přidružené k této asynchronní soket operace.

Metody

Dispose()

Uvolní nespravované prostředky používané SocketAsyncEventArgs instancí a volitelně odstraní spravované prostředky.

Equals(Object)

Určí, zda se zadaný objekt rovná aktuálnímu objektu.

(Zděděno od Object)
Finalize()

Uvolní prostředky používané SocketAsyncEventArgs třídou.

GetHashCode()

Slouží jako výchozí hashovací funkce.

(Zděděno od Object)
GetType()

Získá aktuální Type instanci.

(Zděděno od Object)
MemberwiseClone()

Vytvoří mělkou kopii aktuálního Objectsouboru .

(Zděděno od Object)
OnCompleted(SocketAsyncEventArgs)

Představuje metodu, která je volána při dokončení asynchronní operace.

SetBuffer(Byte[], Int32, Int32)

Nastaví vyrovnávací paměť dat pro použití s asynchronní metodou soketu.

SetBuffer(Int32, Int32)

Nastaví vyrovnávací paměť dat pro použití s asynchronní metodou soketu.

SetBuffer(Memory<Byte>)

Nastaví oblast paměti, která se má použít jako vyrovnávací paměť s asynchronní metodou soketu.

ToString()

Vrátí řetězec, který představuje aktuální objekt.

(Zděděno od Object)

Událost

Completed

Událost použitá k dokončení asynchronní operace.

Platí pro

Viz také