Verwenden von asynchronen ClientsocketsUsing an Asynchronous Client Socket

Ein asynchroner Clientsocket hält die Anwendung nicht an, während darauf gewartet wird, dass Netzwerkvorgänge abgeschlossen werden.An asynchronous client socket does not suspend the application while waiting for network operations to complete. Stattdessen wird das standardmäßige asynchrone Programmiermodell von .NET Framework verwendet, um die Netzwerkverbindung in einem Thread zu verarbeiten, während die Anwendung weiterhin auf dem ursprünglichen Thread ausgeführt wird.Instead, it uses the standard .NET Framework asynchronous programming model to process the network connection on one thread while the application continues to run on the original thread. Asynchrone Sockets eignen sich für Anwendungen, die das Netzwerk stark nutzen, oder die nicht warten können, bis Netzwerkvorgänge vor dem Fortsetzen abgeschlossen werden.Asynchronous sockets are appropriate for applications that make heavy use of the network or that cannot wait for network operations to complete before continuing.

Die Socket-Klasse folgt dem Benennungsmuster von .NET Framework für asynchrone Methoden, z.B. entspricht die synchrone Receive-Methode den asynchronen BeginReceive- und EndReceive-Methoden.The Socket class follows the .NET Framework naming pattern for asynchronous methods; for example, the synchronous Receive method corresponds to the asynchronous BeginReceive and EndReceive methods.

Asynchrone Vorgänge erfordern eine Rückrufmethode, die das Ergebnis des Vorgangs zurückgibt.Asynchronous operations require a callback method to return the result of the operation. Wenn Ihre Anwendung das Ergebnis nicht wissen muss, ist keine Rückrufmethode erforderlich.If your application does not need to know the result, then no callback method is required. Der Beispielcode in diesem Abschnitt veranschaulicht die Verwendung einer Methode zum Start einer Verbindung mit einem Netzwerkgerät und einer Rückrufmethode zum Abschließen der Verbindung, einer Methode zum Start des Datenversands und einer Rückrufmethode zum Abschließen des Versands, einer Methode zum Start des Datenempfangs und einer Rückrufmethode zum Abschließen des Datenempfangs.The example code in this section demonstrates using a method to start connecting to a network device and a callback method to complete the connection, a method to start sending data and a callback method to complete the send, and a method to start receiving data and a callback method to end receiving data.

Asynchrone Sockets verwenden mehrere Threads aus dem Systemthreadpool, um Netzwerkverbindungen zu bearbeiten.Asynchronous sockets use multiple threads from the system thread pool to process network connections. Ein Thread ist verantwortlich für das Initiieren des Datenversands oder Datenempfangs. Andere Threads schließen die Verbindung zum Netzwerkgerät ab und senden oder empfangen Daten.One thread is responsible for initiating the sending or receiving of data; other threads complete the connection to the network device and send or receive the data. In den folgenden Beispielen werden Instanzen der System.Threading.ManualResetEvent-Klasse verwendet, um die Ausführung des Hauptthreads anzuhalten und zu signalisieren, wann die Ausführung fortgesetzt werden kann.In the following examples, instances of the System.Threading.ManualResetEvent class are used to suspend execution of the main thread and signal when execution can continue.

Zur Verbindung eines asynchronen Sockets mit einem Netzwerkgerät initialisiert die Connect-Methode im folgenden Beispiel ein Socket, ruft dann die Socket.Connect-Methode auf und übergibt einen Remoteendpunkt, der das Netzwerkgerät, die Rückrufmethode „Connect“ und ein Zustandsobjekt (der Client-Socket), darstellt. Dieses wird verwendet, um Zustandsinformationen zwischen asynchronen Aufrufen zu übergeben.In the following example, to connect an asynchronous socket to a network device, the Connect method initializes a Socket and then calls the Socket.Connect method, passing a remote endpoint that represents the network device, the connect callback method, and a state object (the client Socket), which is used to pass state information between asynchronous calls. Das Beispiel implementiert die Connect-Methode zur Verbindung des angegebenen Socket mit dem angegebenen Endpunkt.The example implements the Connect method to connect the specified Socket to the specified endpoint. Es wird ein globales ManualResetEvent mit dem Namen connectDone vorausgesetzt.It assumes a global ManualResetEvent named connectDone.

Public Shared Sub Connect(remoteEP As EndPoint, client As Socket)  
    client.BeginConnect(remoteEP, _  
       AddressOf ConnectCallback, client)  
  
    connectDone.WaitOne()  
End Sub 'Connect  
public static void Connect(EndPoint remoteEP, Socket client) {  
    client.BeginConnect(remoteEP,   
        new AsyncCallback(ConnectCallback), client );  
  
   connectDone.WaitOne();  
}  

Die Rückrufmethode „Connect“ ConnectCallback implementiert den AsyncCallback-Delegaten.The connect callback method ConnectCallback implements the AsyncCallback delegate. Sie stellt eine Verbindung mit dem Remotegerät her, wenn das Remotegerät verfügbar ist, und signalisiert dem Thread der Anwendung, dass die Verbindung abgeschlossen ist, indem ManualResetEvent auf connectDone festgelegt wird.It connects to the remote device when the remote device is available and then signals the application thread that the connection is complete by setting the ManualResetEvent connectDone. Im folgenden Code wird die ConnectCallback-Methode implementiert.The following code implements the ConnectCallback method.

Private Shared Sub ConnectCallback(ar As IAsyncResult)  
    Try  
        ' Retrieve the socket from the state object.  
        Dim client As Socket = CType(ar.AsyncState, Socket)  
  
        ' Complete the connection.  
        client.EndConnect(ar)  
  
        Console.WriteLine("Socket connected to {0}", _  
            client.RemoteEndPoint.ToString())  
  
        ' Signal that the connection has been made.  
        connectDone.Set()  
    Catch e As Exception  
        Console.WriteLine(e.ToString())  
    End Try  
End Sub 'ConnectCallback  
private static void ConnectCallback(IAsyncResult ar) {  
    try {  
        // Retrieve the socket from the state object.  
        Socket client = (Socket) ar.AsyncState;  
  
        // Complete the connection.  
        client.EndConnect(ar);  
  
        Console.WriteLine("Socket connected to {0}",  
            client.RemoteEndPoint.ToString());  
  
        // Signal that the connection has been made.  
        connectDone.Set();  
    } catch (Exception e) {  
        Console.WriteLine(e.ToString());  
    }  
}  

Die Beispielmethode Send codiert die angegebenen Zeichenfolgendaten im ASCII-Format und sendet sie asynchron an das Netzwerkgerät, dargestellt durch den angegebenen Socket.The example method Send encodes the specified string data in ASCII format and sends it asynchronously to the network device represented by the specified socket. Das folgende Beispiel implementiert die Send-Methode.The following example implements the Send method.

Private Shared Sub Send(client As Socket, data As [String])  
    ' Convert the string data to byte data using ASCII encoding.  
    Dim byteData As Byte() = Encoding.ASCII.GetBytes(data)  
  
    ' Begin sending the data to the remote device.  
    client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, _  
        AddressOf SendCallback, client)  
End Sub 'Send  
private static void Send(Socket client, String data) {  
    // Convert the string data to byte data using ASCII encoding.  
    byte[] byteData = Encoding.ASCII.GetBytes(data);  
  
    // Begin sending the data to the remote device.  
    client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None,  
        new AsyncCallback(SendCallback), client);  
}  

Die Rückrufmethode „Send“ SendCallback implementiert den AsyncCallback-Delegaten.The send callback method SendCallback implements the AsyncCallback delegate. Die Daten werden gesendet, wenn das Netzwerkgerät für den Empfang bereit ist.It sends the data when the network device is ready to receive. Im folgenden Beispiel wird eine Implementierung der SendCallback-Methode veranschaulicht.The following example shows the implementation of the SendCallback method. Ein globales ManualResetEvent mit dem Namen sendDone wird vorausgesetzt.It assumes a global ManualResetEvent named sendDone.

Private Shared Sub SendCallback(ar As IAsyncResult)  
    Try  
        ' Retrieve the socket from the state object.  
        Dim client As Socket = CType(ar.AsyncState, Socket)  
  
        ' Complete sending the data to the remote device.  
        Dim bytesSent As Integer = client.EndSend(ar)  
        Console.WriteLine("Sent {0} bytes to server.", bytesSent)  
  
        ' Signal that all bytes have been sent.  
        sendDone.Set()  
    Catch e As Exception  
        Console.WriteLine(e.ToString())  
    End Try  
End Sub 'SendCallback  
private static void SendCallback(IAsyncResult ar) {  
    try {  
        // Retrieve the socket from the state object.  
        Socket client = (Socket) ar.AsyncState;  
  
        // Complete sending the data to the remote device.  
        int bytesSent = client.EndSend(ar);  
        Console.WriteLine("Sent {0} bytes to server.", bytesSent);  
  
        // Signal that all bytes have been sent.  
        sendDone.Set();  
    } catch (Exception e) {  
        Console.WriteLine(e.ToString());  
    }  
}  

Das Lesen von Daten aus einem Clientsocket erfordert ein Zustandsobjekt, das Werte zwischen asynchronen Aufrufen übergibt.Reading data from a client socket requires a state object that passes values between asynchronous calls. Die folgende Klasse ist ein Beispielstatusobjekt zum Empfangen von Daten von einem Clientsocket.The following class is an example state object for receiving data from a client socket. Sie enthält ein Feld für den Clientsocket, einen Puffer für die empfangenen Daten und eine StringBuilder, die die eingehende Datenzeichenfolge enthält.It contains a field for the client socket, a buffer for the received data, and a StringBuilder to hold the incoming data string. Wenn Sie diese Felder in das Statusobjekt platzieren, können ihre Werte über mehrere Aufrufe gespeichert werden, damit Daten aus dem Clientsocket gelesen werden können.Placing these fields in the state object allows their values to be preserved across multiple calls to read data from the client socket.

Public Class StateObject  
    ' Client socket.  
    Public workSocket As Socket = Nothing   
    ' Size of receive buffer.  
    Public BufferSize As Integer = 256  
    ' Receive buffer.  
    Public buffer(256) As Byte   
    ' Received data string.  
    Public sb As New StringBuilder()  
End Class 'StateObject  
public class StateObject {  
    // Client socket.  
    public Socket workSocket = null;  
    // Size of receive buffer.  
    public const int BufferSize = 256;  
    // Receive buffer.  
    public byte[] buffer = new byte[BufferSize];  
    // Received data string.  
    public StringBuilder sb = new StringBuilder();  
}  

Die Beispielmethode Receive richtet das Statusobjekt ein, und ruft dann die BeginReceive-Methode auf, um die Daten asynchron aus dem Clientsocket zu lesen.The example Receive method sets up the state object and then calls the BeginReceive method to read the data from the client socket asynchronously. Das folgende Beispiel implementiert die Receive-Methode.The following example implements the Receive method.

Private Shared Sub Receive(client As Socket)  
    Try  
        ' Create the state object.  
        Dim state As New StateObject()  
        state.workSocket = client  
  
        ' Begin receiving the data from the remote device.  
        client.BeginReceive(state.buffer, 0, state.BufferSize, 0, _  
            AddressOf ReceiveCallback, state)  
    Catch e As Exception  
        Console.WriteLine(e.ToString())  
    End Try  
End Sub 'Receive  
private static void Receive(Socket client) {  
    try {  
        // Create the state object.  
        StateObject state = new StateObject();  
        state.workSocket = client;  
  
        // Begin receiving the data from the remote device.  
        client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,  
            new AsyncCallback(ReceiveCallback), state);  
    } catch (Exception e) {  
        Console.WriteLine(e.ToString());  
    }  
}  

Die Rückruffunktion „Receive“ ReceiveCallback implementiert den AsyncCallback-Delegaten.The receive callback method ReceiveCallback implements the AsyncCallback delegate. Sie erhält die Daten aus dem Netzwerkgerät und erstellt eine Meldungszeichenfolge.It receives the data from the network device and builds a message string. Diese Methode liest ein oder mehrere Bytes vom Netzwerk in den Datenpuffer und ruft dann die BeginReceive-Methode erneut auf, sobald die vom Client gesendeten Daten vollständig sind.It reads one or more bytes of data from the network into the data buffer and then calls the BeginReceive method again until the data sent by the client is complete. Nachdem alle Daten vom Client gelesen wurden, signalisiert ReceiveCallback dem Thread der Anwendung, dass die Daten vollständig sind, indem ManualResetEvent auf sendDone festgelegt wurde.Once all the data is read from the client, ReceiveCallback signals the application thread that the data is complete by setting the ManualResetEvent sendDone.

Der folgende Beispielcode implementiert die ReceiveCallback-Methode.The following example code implements the ReceiveCallback method. Es wird eine globale Zeichenfolge mit dem Namen response vorausgesetzt, die die empfangene Zeichenfolge und ein globales ManualResetEvent mit dem Namen receiveDone enthält.It assumes a global string named response that holds the received string and a global ManualResetEvent named receiveDone. Der Server muss den Clientsocket ordnungsgemäß beenden, um die Netzwerksitzung herunterzufahren.The server must shut down the client socket gracefully to end the network session.

Private Shared Sub ReceiveCallback(ar As IAsyncResult)  
    Try  
        ' Retrieve the state object and the client socket   
        ' from the asynchronous state object.  
        Dim state As StateObject = CType(ar.AsyncState, StateObject)  
        Dim client As Socket = state.workSocket  
  
        ' Read data from the remote device.  
        Dim bytesRead As Integer = client.EndReceive(ar)  
  
        If bytesRead > 0 Then  
            ' There might be more data, so store the data received so far.  
            state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, _  
                bytesRead))  
  
            '  Get the rest of the data.  
            client.BeginReceive(state.buffer, 0, state.BufferSize, 0, _  
                AddressOf ReceiveCallback, state)  
        Else  
            ' All the data has arrived; put it in response.  
            If state.sb.Length > 1 Then  
                response = state.sb.ToString()  
            End If  
            ' Signal that all bytes have been received.  
            receiveDone.Set()  
        End If  
    Catch e As Exception  
        Console.WriteLine(e.ToString())  
    End Try  
End Sub 'ReceiveCallback  
private static void ReceiveCallback( IAsyncResult ar ) {  
    try {  
        // Retrieve the state object and the client socket   
        // from the asynchronous state object.  
        StateObject state = (StateObject) ar.AsyncState;  
        Socket client = state.workSocket;  
        // Read data from the remote device.  
        int bytesRead = client.EndReceive(ar);  
        if (bytesRead > 0) {  
            // There might be more data, so store the data received so far.  
            state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));  
                //  Get the rest of the data.  
            client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,  
                new AsyncCallback(ReceiveCallback), state);  
        } else {  
            // All the data has arrived; put it in response.  
            if (state.sb.Length > 1) {  
                response = state.sb.ToString();  
            }  
            // Signal that all bytes have been received.  
            receiveDone.Set();  
        }  
    } catch (Exception e) {  
        Console.WriteLine(e.ToString());  
    }  
}  

Siehe auchSee also