C# SocketAsyncEventArgs类

Stella981
• 阅读 431
  • 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方法。)
          // <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(用于每个套接字I/O操作的缓冲区大小)</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.
          //(通过预先分配可重用的缓冲区和上下文对象初始化服务器。这些对象不需要预先分配或重用,而是通过这种方式来说明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);
          }
      
      }
    

    待续

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Flink SQL Window源码全解析
!(https://oscimg.oschina.net/oscnet/72793fbade36fc18d649681ebaeee4cdf00.jpg)(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzU3MzgwNT
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这