C# SocketAsyncEventArgs类

  • Namespace:System.Net.Sockets
  • Assemblies:System.Net.Sockets.dll, System.dll, netstandard.dll
  • (Represents an asynchronous socket operation)代表一个异步套接字操作:
  • public class SocketAsyncEventArgs : EventArgs, IDisposable

    Inheritance(继承) Object-> EventArgs->SocketAsyncEventArgs

    Implements(实现) IDisposable

    实例

    下面的代码示例实现连接逻辑使用套接字服务器socketasynceventargs类接受连接后,从客户端读取所有数据发送回客户端。读和回声返回到客户端模式直到客户端断开连接。缓冲管理器类,通过这个例子,用于在代码示例显示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 (用于每个套接字I/O操作的缓冲区大小)
    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(可重用SocketAsyncEventArgs对象池,用于编写、读取和接受套接字操作)
    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 调用init方法,然后调用Start方法 
   
    //本类的构造函数Server(int, int)
    // <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously(本被设计为同时处理的最大连接数)</param>
    //参数numConnections:本例被涉及的同时处理的最大连接数。
    // <param name="receiveBufferSize">buffer size to use for each socket I/O operation(用于每个套接字I/O操作的缓冲区大小)</param>
    //参数receiceBufferSize:用于每个套接字I/O操作的缓冲区大小。
    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.
    //(通过预先分配可重用的缓冲区和上下文对象初始化服务器。这些对象不需要预先分配或重用,而是通过这种方式来说明API是如何容易地被用来创建可重用对象以提高服务器性能的。)
    public void Init()
    {
        // Allocates one large byte buffer which all I/O operations use a piece of.  This gaurds 
        // against memory fragmentation(分配一个大字节缓冲区,所有I/O操作都使用一个。
这是反对记忆碎片的)
        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(指定从缓冲池字节缓冲区的socketasynceventarg对象)
            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
        StartAccept(null);            

        //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)
    {
        if (acceptEventArg == null)
        {
            acceptEventArg = new SocketAsyncEventArgs();
            acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
        }
        else
        {
            // socket must be cleared since the context object is being reused
            acceptEventArg.AcceptSocket = null;
        }

        m_maxNumberAcceptedClients.WaitOne();
        bool 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);
    }

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

        // Accept the next connection request
        StartAccept(e);
    }

    // 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);
        m_maxNumberAcceptedClients.Release();
        Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets);

        // Free the SocketAsyncEventArg so they can be reused by another client
        m_readWritePool.Push(e);
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东方猫

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值