SocketAsyncEventArgs Klasse

Definition

Stellt einen asynchronen Socketvorgang dar.

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
Vererbung
SocketAsyncEventArgs
Implementiert

Beispiele

Im folgenden Codebeispiel wird die Verbindungslogik für den Socketserver implementiert, der die SocketAsyncEventArgs -Klasse verwendet. Nach dem Akzeptieren einer Verbindung werden alle vom Client gelesenen Daten an den Client zurückgesendet. Das Lese- und Echo-Zurück zum Clientmuster wird fortgesetzt, bis die Verbindung des Clients getrennt wird. Die BufferManager-Klasse, die in diesem Beispiel verwendet wird, wird im Codebeispiel für die SetBuffer(Byte[], Int32, Int32) -Methode angezeigt. Die SocketAsyncEventArgsPool-Klasse, die in diesem Beispiel verwendet wird, wird im Codebeispiel für den SocketAsyncEventArgs Konstruktor angezeigt.

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

Hinweise

Die SocketAsyncEventArgs -Klasse ist Teil einer Reihe von Verbesserungen der -Klasse, die System.Net.Sockets.Socket ein alternatives asynchrones Muster bereitstellen, das von spezialisierten Hochleistungs-Socketanwendungen verwendet werden kann. Diese Klasse wurde speziell für Netzwerkserveranwendungen entwickelt, die eine hohe Leistung erfordern. Eine Anwendung kann das erweiterte asynchrone Muster ausschließlich oder nur in bestimmten heißen Bereichen (z. B. beim Empfang großer Datenmengen) verwenden.

Die Hauptfunktion dieser Erweiterungen ist die Vermeidung der wiederholten Zuordnung und Synchronisierung von Objekten während asynchroner Socket-E/A mit hohem Volumen. Das derzeit von der System.Net.Sockets.Socket -Klasse implementierte Start/End-Entwurfsmuster erfordert die Zuordnung eines System.IAsyncResult Objekts für jeden asynchronen Socketvorgang.

In den neuen System.Net.Sockets.Socket Klassenerweiterungen werden asynchrone Socketvorgänge durch wiederverwendbare SocketAsyncEventArgs Objekte beschrieben, die von der Anwendung zugewiesen und verwaltet werden. Socketanwendungen mit hoher Leistung kennen die Menge an überlappenden Socketvorgängen, die aufrechterhalten werden müssen, am besten. Die Anwendung kann so viele SocketAsyncEventArgs-Objekte erstellen wie nötig. Wenn eine Serveranwendung beispielsweise über 15 ausstehende Socketakzept-Vorgänge benötigt, um eingehende Clientverbindungsraten zu unterstützen, kann sie zu diesem Zweck 15 wiederverwendbare SocketAsyncEventArgs Objekte zuordnen.

Das Muster zum Ausführen eines asynchronen Socketvorgangs mit dieser Klasse besteht aus den folgenden Schritten:

  1. Zuweisen eines neuen SocketAsyncEventArgs-Kontextobjekt oder Abrufen eines kostenlosen aus einem Anwendungspool.

  2. Legen Sie die Eigenschaften für das Kontextobjekt auf den Vorgang fest, der gerade ausgeführt werden soll (z. B. die Vervollständigungsrückrufmethode, den Datenpuffer, den Offset in den Puffer und die maximale Menge an zu übertragenden Daten).

  3. Aufrufen der entsprechenden Socketmethode (XxxAsync) zum Initiieren des asynchronen Vorgangs.

  4. Wenn die asynchrone Socketmethode (xxxAsync) true zurückgibt, fragen Sie im Rückruf die Kontexteigenschaften nach Abschlussstatus ab.

  5. Wenn die asynchrone Socketmethode (xxxAsync) false zurückgibt, wurde der Vorgang synchron abgeschlossen. Die Kontexteigenschaften könnten möglicherweise für das Betriebsergebnis abgefragt werden.

  6. Verwenden Sie den Kontext für einen anderen Vorgang erneut, fügen Sie ihn wieder in den Pool ein, oder verwerfen Sie ihn.

Die Lebensdauer des neuen Kontextobjekts für den asynchronen Socketvorgang wird durch Verweise durch den Anwendungscode und asynchrone E/A-Verweise bestimmt. Es ist nicht erforderlich, dass die Anwendung einen Verweis auf das Kontextobjekt des asynchronen Socketvorgangs beibehält, nachdem er als Parameter an eine der Methoden des asynchronen Socketvorgangs gesendet wurde. Der Verweis bleibt bestehen, bis der Abschlussrückruf zurückgegeben wird. Für die Anwendung ist es jedoch vorteilhaft, den Verweis auf den Kontext beizubehalten, damit er für einen zukünftigen asynchronen Socketvorgang wiederverwendet werden kann.

Konstruktoren

SocketAsyncEventArgs()

Erstellt eine leere SocketAsyncEventArgs-Instanz.

SocketAsyncEventArgs(Boolean)

Initialisiert das SocketAsyncEventArgs.

Eigenschaften

AcceptSocket

Ruft den Socket ab, der zum Akzeptieren einer Verbindung mit einer asynchronen Socketmethode erstellt wird, oder legt ihn fest.

Buffer

Ruft den Datenpuffer ab, der mit einer asynchronen Socketmethode verwendet werden soll.

BufferList

Ruft ein Array von Datenpuffern ab, die mit einer asynchronen Socketmethode verwendet werden sollen, oder legt es fest.

BytesTransferred

Ruft die Anzahl der im Socketvorgang übertragenen Bytes ab.

ConnectByNameError

Ruft die Ausnahme im Fall eines Verbindungsfehlers ab, wenn DnsEndPoint verwendet wurde.

ConnectSocket

Das erstellte und verbundene Socket-Objekt nach dem erfolgreichen Beenden der ConnectAsync-Methode.

Count

Ruft die maximale Datenmenge in Bytes ab, die in einem asynchronen Vorgang gesendet oder empfangen wird.

DisconnectReuseSocket

Ruft einen Wert ab, der angibt, ob ein Socket nach einem Trennvorgang wiederverwendet werden kann, oder legt ihn fest.

LastOperation

Ruft den Typ des Socketvorgangs ab, der zuletzt mit diesem Kontextobjekt ausgeführt wurde.

MemoryBuffer

Ruft den Arbeitsspeicherbereich ab, der als Puffer mit einer asynchronen Socketmethode verwendet werden soll.

Offset

Ruft den Offset in Bytes im Datenpuffer ab, auf den von der Buffer-Eigenschaft verwiesen wird.

ReceiveMessageFromPacketInfo

Ruft die IP-Adresse und Schnittstelle eines empfangenen Pakets ab.

RemoteEndPoint

Ruft den Remote-IP-Endpunkt für einen asynchronen Vorgang ab oder legt ihn fest.

SendPacketsElements

Ruft ein Array von Puffern ab, die für einen von der SendPacketsAsync(SocketAsyncEventArgs)-Methode verwendeten asynchronen Vorgang gesendet werden sollen, oder legt es fest.

SendPacketsFlags

Ruft eine bitweise Kombination von TransmitFileOptions-Werten für einen asynchronen Vorgang ab, der von der SendPacketsAsync(SocketAsyncEventArgs)-Methode verwendet wird, oder legt sie fest.

SendPacketsSendSize

Ruft die Größe des im Sendevorgang verwendeten Datenblocks in Bytes ab oder legt diese fest.

SocketClientAccessPolicyProtocol
Veraltet.

Ruft das Protokoll ab oder legt es fest, das verwenden wird, um die Socketclient-Zugriffsrichtliniendatei herunterzuladen.

SocketError

Ruft das Ergebnis des asynchronen Socketvorgangs ab oder legt dieses fest.

SocketFlags

Ruft die Ergebnisse eines asynchronen Socketvorgangs ab oder legt das Verhalten eines asynchronen Vorgangs fest.

UserToken

Ruft ein Benutzer- oder Anwendungsobjekt ab, das diesem asynchronen Socketvorgang zugeordnet ist, oder legt es fest.

Methoden

Dispose()

Gibt die von der SocketAsyncEventArgs-Instanz verwendeten nicht verwalteten Ressourcen zurück und verwirft optional die verwalteten Ressourcen.

Equals(Object)

Bestimmt, ob das angegebene Objekt gleich dem aktuellen Objekt ist.

(Geerbt von Object)
Finalize()

Gibt von der SocketAsyncEventArgs-Klasse verwendete Ressourcen frei.

GetHashCode()

Fungiert als Standardhashfunktion.

(Geerbt von Object)
GetType()

Ruft den Type der aktuellen Instanz ab.

(Geerbt von Object)
MemberwiseClone()

Erstellt eine flache Kopie des aktuellen Object.

(Geerbt von Object)
OnCompleted(SocketAsyncEventArgs)

Stellt eine Methode dar, die beim Abschluss eines asynchronen Vorgangs aufgerufen wird.

SetBuffer(Byte[], Int32, Int32)

Legt den Datenpuffer fest, der mit einer asynchronen Socketmethode verwendet werden soll.

SetBuffer(Int32, Int32)

Legt den Datenpuffer fest, der mit einer asynchronen Socketmethode verwendet werden soll.

SetBuffer(Memory<Byte>)

Legt den Arbeitsspeicherbereich fest, der als Puffer mit einer asynchronen Socketmethode verwendet werden soll.

ToString()

Gibt eine Zeichenfolge zurück, die das aktuelle Objekt darstellt.

(Geerbt von Object)

Ereignisse

Completed

Das Ereignis, das zum Abschließen eines asynchronen Vorgangs verwendet wird.

Gilt für:

Weitere Informationen