SocketAsyncEventArgs クラス

定義

非同期ソケット操作を表します。

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
継承
SocketAsyncEventArgs
実装

次のコード例では、クラスを使用するソケット サーバーの接続ロジックを SocketAsyncEventArgs 実装します。 接続を受け入れると、クライアントから読み取られたすべてのデータがクライアントに返送されます。 クライアント が切断されるまで、クライアント パターンへの読み取りとエコーが続行されます。 この例で使用される BufferManager クラスは、メソッドのコード例に SetBuffer(Byte[], Int32, Int32) 表示されます。 この例で使用されている SocketAsyncEventArgsPool クラスは、コンストラクターのコード例に 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);
    }
}

注釈

この SocketAsyncEventArgs クラスは、特殊化された高性能ソケット アプリケーションで使用できる代替非同期パターンを提供する、クラスの一連の機能強化 System.Net.Sockets.Socket の一部です。 このクラスは、高パフォーマンスを必要とするネットワーク サーバー アプリケーション向けに特別に設計されています。 アプリケーションでは、拡張非同期パターンを排他的に使用することも、ターゲットとするホットエリアでのみ使用することもできます (大量のデータを受信する場合など)。

この機能強化の主な特徴は、高ボリュームの非同期ソケット I/O 中、オブジェクトの割り当てと同期が繰り返されることを避けることにあります。 クラスによって System.Net.Sockets.Socket 現在実装されている Begin/End デザイン パターンでは、 System.IAsyncResult 非同期ソケット操作ごとにオブジェクトを割り当てる必要があります。

新しい System.Net.Sockets.Socket クラスの機能強化では、非同期ソケット操作は、アプリケーションによって割り当てられ、維持される再利用可能な SocketAsyncEventArgs オブジェクトによって記述されます。 高パフォーマンスのソケット アプリケーションは、維持する必要があるオーバーラップしたソケット操作の量を効率的に認識します。 アプリケーションは SocketAsyncEventArgs オブジェクトを必要な数だけ作成できます。 たとえば、受信クライアント接続レートをサポートするために、サーバー アプリケーションが常に未処理の 15 個のソケット受け入れ操作を持つ必要がある場合は、その目的のために 15 個の再利用可能な SocketAsyncEventArgs オブジェクトを割り当てることができます。

このクラスで非同期ソケット操作を実行するパターンは次の手順で構成されます。

  1. 新しい SocketAsyncEventArgs コンテキスト オブジェクトを割り当てるか、アプリケーション プールから空きコンテキスト オブジェクトを入手します。

  2. コンテキスト オブジェクトのプロパティを、実行される操作 (完了コールバック メソッド、データ バッファー、バッファーへのオフセット、転送するデータの最大量など) に設定します。

  3. 適切なソケット メソッド (xxxAsync) を呼び出し、非同期操作を開始します。

  4. 非同期ソケット メソッド (xxxAsync) が true を返す場合は、コールバックでコンテキスト プロパティに対してクエリを実行して完了状態を確認します。

  5. 非同期ソケット メソッド (xxxAsync) が false を返す場合、操作は同期的に完了しました。 コンテキスト プロパティに操作結果が問い合わされることがあります。

  6. 別の操作でコンテキストを再利用するか、プールに戻すか、破棄します。

新しい非同期ソケット操作コンテキスト オブジェクトの有効期間は、アプリケーション コードと非同期 I/O 参照による参照によって決まります。 非同期ソケット操作メソッドの 1 つにパラメーターとして送信された後、非同期ソケット操作コンテキスト オブジェクトの参照をアプリケーションが維持する必要はありません。 完了コールバックが戻るまで、参照状態が維持されます。 ただし、将来の非同期ソケット操作で再利用できるように、アプリケーションがコンテキストへの参照を保持すると便利です。

コンストラクター

SocketAsyncEventArgs()

空の SocketAsyncEventArgs インスタンスを作成します。

SocketAsyncEventArgs(Boolean)

SocketAsyncEventArgs を初期化します。

プロパティ

AcceptSocket

非同期ソケット メソッドとの接続を受け入れるために使用するソケットまたは作成されたソケットを取得または設定します。

Buffer

非同期ソケット メソッドで使用するデータ バッファーを取得します。

BufferList

非同期ソケット メソッドで使用するデータ バッファーの配列を取得または設定します。

BytesTransferred

ソケット操作で転送するバイト数を取得します。

ConnectByNameError

DnsEndPoint が使用されているときに接続エラーが発生した場合に、例外を取得します。

ConnectSocket

ConnectAsync メソッドが正常に完了した後に作成され、接続された Socket オブジェクト。

Count

非同期操作で送信または受信するデータの最大量 (バイト単位) を取得します。

DisconnectReuseSocket

切断操作後にソケットを再利用できるかどうかを指定する値を取得または設定します。

LastOperation

このコンテキスト オブジェクトで最近実行されたソケット操作の種類を取得します。

MemoryBuffer

非同期ソケット メソッドでバッファーとして使用するメモリ領域を取得します。

Offset

Buffer プロパティによって参照されるデータ バッファーへのオフセット (バイト単位) を取得します。

ReceiveMessageFromPacketInfo

受信パケットの IP アドレスとインターフェイスを取得します。

RemoteEndPoint

非同期操作のリモート IP エンドポイントを取得または設定します。

SendPacketsElements

非同期操作のために送信するバッファーの配列を取得または設定します。この配列は、SendPacketsAsync(SocketAsyncEventArgs) メソッドで使用します。

SendPacketsFlags

非同期操作で使用する TransmitFileOptions 値のビットごとの組み合わせを取得または設定します。この組み合わせは、SendPacketsAsync(SocketAsyncEventArgs) メソッドで使用します。

SendPacketsSendSize

送信操作で使用するデータ ブロックのサイズ (バイト単位) を取得または設定します。

SocketClientAccessPolicyProtocol
互換性のために残されています。

ソケット クライアント アクセス ポリシー ファイルをダウンロードするために使用するプロトコルを取得または設定します。

SocketError

非同期ソケット操作の結果を取得または設定します。

SocketFlags

非同期ソケット操作の結果を取得します。または、非同期操作の動作を設定します。

UserToken

この非同期ソケット操作に関連付けられたユーザー オブジェクトまたはアプリケーション オブジェクトを取得または設定します。

メソッド

Dispose()

SocketAsyncEventArgs インスタンスが使用するアンマネージド リソースを解放し、必要に応じてマネージド リソースを破棄します。

Equals(Object)

指定されたオブジェクトが現在のオブジェクトと等しいかどうかを判断します。

(継承元 Object)
Finalize()

SocketAsyncEventArgs クラスによって使用されていたリソースを解放します。

GetHashCode()

既定のハッシュ関数として機能します。

(継承元 Object)
GetType()

現在のインスタンスの Type を取得します。

(継承元 Object)
MemberwiseClone()

現在の Object の簡易コピーを作成します。

(継承元 Object)
OnCompleted(SocketAsyncEventArgs)

非同期操作の完了時に呼び出されるメソッドを表します。

SetBuffer(Byte[], Int32, Int32)

非同期ソケット メソッドで使用するデータ バッファーを設定します。

SetBuffer(Int32, Int32)

非同期ソケット メソッドで使用するデータ バッファーを設定します。

SetBuffer(Memory<Byte>)

非同期ソケット メソッドでバッファーとして使用するメモリ領域を設定します。

ToString()

現在のオブジェクトを表す文字列を返します。

(継承元 Object)

events

Completed

非同期操作を完了させるために使用されるイベントです。

適用対象

こちらもご覧ください