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

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

注解

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 引用的引用决定。 作为参数提交给异步套接字操作方法之一后,应用程序不必保留对异步套接字操作上下文对象的引用。 完成回调返回之前,应用程序会继续引用它。 但是,应用程序最好保留对上下文的引用,以便将来的异步套接字操作可以重复使用该引用。

构造函数

SocketAsyncEventArgs()

创建一个空的 SocketAsyncEventArgs 实例。

SocketAsyncEventArgs(Boolean)

初始化 SocketAsyncEventArgs

属性

AcceptSocket

获取或设置要使用的套接字或创建用于接受与异步套接字方法的连接的套接字。

Buffer

获取要用于异步套接字方法的数据缓冲区。

BufferList

获取或设置一个要用于异步套接字方法的数据缓冲区数组。

BytesTransferred

获取在套接字操作中传输的字节数。

ConnectByNameError

当使用 DnsEndPoint 时,在出现连接故障的情况下获取异常。

ConnectSocket

成功完成 Socket 方法后创建和连接的 ConnectAsync 对象。

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)

事件

Completed

用于完成异步操作的事件。

适用于

另请参阅