SocketAsyncEventArgs Klas

Definitie

Vertegenwoordigt een asynchrone socketbewerking.

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
Overname
SocketAsyncEventArgs
Implementeringen

Voorbeelden

In het volgende codevoorbeeld wordt de verbindingslogica geïmplementeerd voor de socketserver die gebruikmaakt van de SocketAsyncEventArgs klasse. Nadat u een verbinding hebt geaccepteerd, worden alle gegevens die van de client worden gelezen, teruggestuurd naar de client. Het lees- en echopatroon naar het clientpatroon wordt voortgezet totdat de verbinding met de client wordt verbroken. De BufferManager-klasse die in dit voorbeeld wordt gebruikt, wordt weergegeven in het codevoorbeeld voor de SetBuffer(Byte[], Int32, Int32) methode. De klasse SocketAsyncEventArgsPool die in dit voorbeeld wordt gebruikt, wordt weergegeven in het codevoorbeeld voor de 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);

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

Opmerkingen

De SocketAsyncEventArgs klasse maakt deel uit van een reeks verbeteringen aan de System.Net.Sockets.Socket klasse die een alternatief asynchroon patroon bieden dat kan worden gebruikt door gespecialiseerde sockettoepassingen met hoge prestaties. Deze klasse is speciaal ontworpen voor netwerkservertoepassingen waarvoor hoge prestaties zijn vereist. Een toepassing kan het verbeterde asynchrone patroon uitsluitend gebruiken of alleen in gerichte hot-gebieden (bijvoorbeeld bij het ontvangen van grote hoeveelheden gegevens).

De belangrijkste functie van deze verbeteringen is het vermijden van de herhaalde toewijzing en synchronisatie van objecten tijdens asynchrone socket I/O van grote volumes. Voor het ontwerppatroon Begin/Einde dat momenteel door de System.Net.Sockets.Socket klasse wordt geïmplementeerd, moet een System.IAsyncResult object worden toegewezen voor elke asynchrone socketbewerking.

In de nieuwe System.Net.Sockets.Socket klasseverbeteringen worden asynchrone socketbewerkingen beschreven door herbruikbare SocketAsyncEventArgs objecten die door de toepassing worden toegewezen en onderhouden. Krachtige sockettoepassingen kennen het beste de hoeveelheid overlappende socketbewerkingen die moeten worden voortgezet. De toepassing kan zoveel objecten SocketAsyncEventArgs maken die nodig zijn. Als een servertoepassing bijvoorbeeld te allen tijde 15 socket-acceptbewerkingen moet hebben om binnenkomende clientverbindingssnelheden te ondersteunen, kunnen er 15 herbruikbare SocketAsyncEventArgs objecten voor dat doel worden toegewezen.

Het patroon voor het uitvoeren van een asynchrone socketbewerking met deze klasse bestaat uit de volgende stappen:

  1. Wijs een nieuw SocketAsyncEventArgs contextobject toe of ontvang een gratis object uit een groep toepassingen.

  2. Stel eigenschappen voor het contextobject in op de bewerking die moet worden uitgevoerd (de callbackmethode voor voltooiing, de gegevensbuffer, de offset in de buffer en de maximale hoeveelheid gegevens die moet worden overgedragen, bijvoorbeeld).

  3. Roep de juiste socketmethode (xxxAsync) aan om de asynchrone bewerking te initiëren.

  4. Als de asynchrone socketmethode (xxxAsync) waar retourneert, voert u in de callback een query uit op de contexteigenschappen voor de voltooiingsstatus.

  5. Als de asynchrone socketmethode (xxxAsync) onwaar retourneert, is de bewerking synchroon voltooid. De contexteigenschappen kunnen worden opgevraagd voor het bewerkingsresultaat.

  6. Gebruik de context voor een andere bewerking opnieuw, plaats deze weer in de pool of verwijder deze.

De levensduur van het nieuwe contextobject voor asynchrone socketbewerkingen wordt bepaald door verwijzingen door de toepassingscode en asynchrone I/O-verwijzingen. Het is niet nodig voor de toepassing om een verwijzing naar een asynchroon socketbewerkingscontextobject te behouden nadat deze als parameter is verzonden naar een van de asynchrone socketbewerkingsmethoden. Er wordt naar verwezen totdat de callback voor voltooiing retourneert. Het is echter voordelig voor de toepassing om de verwijzing naar de context te behouden, zodat deze opnieuw kan worden gebruikt voor een toekomstige asynchrone socketbewerking.

Constructors

Name Description
SocketAsyncEventArgs()

Hiermee maakt u een leeg SocketAsyncEventArgs exemplaar.

Eigenschappen

Name Description
AcceptSocket

Hiermee haalt u de socket op of stelt u de socket in die is gemaakt voor het accepteren van een verbinding met een asynchrone socketmethode.

Buffer

Hiermee haalt u de gegevensbuffer op die moet worden gebruikt met een asynchrone socketmethode.

BufferList

Hiermee wordt een matrix van gegevensbuffers opgehaald of ingesteld voor gebruik met een asynchrone socketmethode.

BytesTransferred

Hiermee haalt u het aantal overgedragen bytes op in de socketbewerking.

ConnectByNameError

Hiermee wordt de uitzondering opgehaald in het geval van een verbindingsfout bij gebruik van een DnsEndPoint verbinding.

ConnectSocket

Het gemaakte en verbonden Socket object na voltooiing van de ConnectAsync methode.

Count

Hiermee wordt de maximale hoeveelheid gegevens, in bytes, opgehaald voor het verzenden of ontvangen van gegevens in een asynchrone bewerking.

DisconnectReuseSocket

Hiermee haalt u een waarde op die aangeeft of socket opnieuw kan worden gebruikt na een verbroken bewerking.

LastOperation

Hiermee wordt het type socketbewerking opgehaald dat het laatst is uitgevoerd met dit contextobject.

MemoryBuffer

Hiermee haalt u het geheugengebied op dat moet worden gebruikt als buffer met een asynchrone socketmethode.

Offset

Hiermee haalt u de offset in bytes op in de gegevensbuffer waarnaar wordt verwezen door de Buffer eigenschap.

ReceiveMessageFromPacketInfo

Hiermee haalt u het IP-adres en de interface van een ontvangen pakket op.

RemoteEndPoint

Hiermee wordt het externe IP-eindpunt voor een asynchrone bewerking ophaalt of ingesteld.

SendPacketsElements

Hiermee kunt u een matrix van buffers ophalen of instellen die moeten worden verzonden voor een asynchrone bewerking die door de SendPacketsAsync(SocketAsyncEventArgs) methode wordt gebruikt.

SendPacketsFlags

Haalt een bitsgewijze combinatie van TransmitFileOptions waarden op of stelt deze in voor een asynchrone bewerking die door de SendPacketsAsync(SocketAsyncEventArgs) methode wordt gebruikt.

SendPacketsSendSize

Hiermee wordt de grootte, in bytes, van het gegevensblok opgehaald of ingesteld dat in de verzendbewerking wordt gebruikt.

SocketClientAccessPolicyProtocol
Verouderd.

Hiermee haalt u het protocol op dat moet worden gebruikt voor het downloaden van het socket-clienttoegangsbeleidsbestand.

SocketError

Hiermee haalt u het resultaat van de asynchrone socketbewerking op of stelt u deze in.

SocketFlags

Hiermee worden de resultaten van een asynchrone socketbewerking opgehaald of wordt het gedrag van een asynchrone bewerking ingesteld.

UserToken

Hiermee haalt u een gebruiker of toepassingsobject op dat is gekoppeld aan deze asynchrone socketbewerking.

Methoden

Name Description
Dispose()

Publiceert de niet-beheerde resources die door het SocketAsyncEventArgs exemplaar worden gebruikt en verwijdert desgewenst de beheerde resources.

Equals(Object)

Bepaalt of het opgegeven object gelijk is aan het huidige object.

(Overgenomen van Object)
Finalize()

Hiermee worden resources vrijgemaakt die door de SocketAsyncEventArgs klasse worden gebruikt.

GetHashCode()

Fungeert als de standaardhashfunctie.

(Overgenomen van Object)
GetType()

Hiermee haalt u de Type huidige instantie op.

(Overgenomen van Object)
MemberwiseClone()

Hiermee maakt u een ondiepe kopie van de huidige Object.

(Overgenomen van Object)
OnCompleted(SocketAsyncEventArgs)

Vertegenwoordigt een methode die wordt aangeroepen wanneer een asynchrone bewerking is voltooid.

SetBuffer(Byte[], Int32, Int32)

Hiermee stelt u de gegevensbuffer in voor gebruik met een asynchrone socketmethode.

SetBuffer(Int32, Int32)

Hiermee stelt u de gegevensbuffer in voor gebruik met een asynchrone socketmethode.

SetBuffer(Memory<Byte>)

Hiermee stelt u het geheugengebied in dat moet worden gebruikt als buffer met een asynchrone socketmethode.

ToString()

Retourneert een tekenreeks die het huidige object vertegenwoordigt.

(Overgenomen van Object)

gebeurtenis

Name Description
Completed

De gebeurtenis die wordt gebruikt om een asynchrone bewerking te voltooien.

Van toepassing op

Zie ook