zoukankan      html  css  js  c++  java
  • SocketAsyncEvent方式的Server

    1.AsyncUserToken

     1 public class AsyncUserToken
     2 {
     3     /// <summary>  
     4     /// 客户端IP地址  
     5     /// </summary>  
     6     public IPAddress IPAddress { get; set; }
     7 
     8     /// <summary>  
     9     /// 远程地址  
    10     /// </summary>  
    11     public EndPoint Remote { get; set; }
    12 
    13     /// <summary>  
    14     /// 通信SOKET  
    15     /// </summary>  
    16     public Socket Socket { get; set; }
    17 
    18     /// <summary>  
    19     /// 连接时间  
    20     /// </summary>  
    21     public DateTime ConnectTime { get; set; }
    22 
    23     /// <summary>  
    24     /// 数据缓存区  
    25     /// </summary>  
    26     public List<byte> Buffer { get; set; }
    27 
    28     public AsyncUserToken()
    29     {
    30         this.Buffer = new List<byte>();
    31     }
    32 }
    View Code

    2.SocketAsyncEventArgsPool

     1 public class SocketAsyncEventArgsPool
     2 {
     3     Stack<SocketAsyncEventArgs> m_pool;
     4 
     5     // Initializes the object pool to the specified size
     6     //
     7     // The "capacity" parameter is the maximum number of 
     8     // SocketAsyncEventArgs objects the pool can hold
     9     public SocketAsyncEventArgsPool(int capacity)
    10     {
    11         m_pool = new Stack<SocketAsyncEventArgs>(capacity);
    12     }
    13 
    14     // Add a SocketAsyncEventArg instance to the pool
    15     //
    16     //The "item" parameter is the SocketAsyncEventArgs instance 
    17     // to add to the pool
    18     public void Push(SocketAsyncEventArgs item)
    19     {
    20         if (item == null) { throw new ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); }
    21         lock (m_pool)
    22         {
    23             m_pool.Push(item);
    24         }
    25     }
    26 
    27     // Removes a SocketAsyncEventArgs instance from the pool
    28     // and returns the object removed from the pool
    29     public SocketAsyncEventArgs Pop()
    30     {
    31         lock (m_pool)
    32         {
    33             return m_pool.Pop();
    34         }
    35     }
    36 
    37     // The number of SocketAsyncEventArgs instances in the pool
    38     public int Count
    39     {
    40         get { return m_pool.Count; }
    41     }
    42 
    43 }
    View Code

    3.BufferManager

     1 public class BufferManager
     2 {
     3     int m_numBytes;                 // the total number of bytes controlled by the buffer pool
     4     byte[] m_buffer;                // the underlying byte array maintained by the Buffer Manager
     5     Stack<int> m_freeIndexPool;     // 
     6     int m_currentIndex;
     7     int m_bufferSize;
     8 
     9     public BufferManager(int totalBytes, int bufferSize)
    10     {
    11         m_numBytes = totalBytes;
    12         m_currentIndex = 0;
    13         m_bufferSize = bufferSize;
    14         m_freeIndexPool = new Stack<int>();
    15     }
    16 
    17     // Allocates buffer space used by the buffer pool
    18     public void InitBuffer()
    19     {
    20         // create one big large buffer and divide that 
    21         // out to each SocketAsyncEventArg object
    22         m_buffer = new byte[m_numBytes];
    23     }
    24 
    25     // Assigns a buffer from the buffer pool to the 
    26     // specified SocketAsyncEventArgs object
    27     //
    28     // <returns>true if the buffer was successfully set, else false</returns>
    29     public bool SetBuffer(SocketAsyncEventArgs args)
    30     {
    31 
    32         if (m_freeIndexPool.Count > 0)
    33         {
    34             args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize);
    35         }
    36         else
    37         {
    38             if ((m_numBytes - m_bufferSize) < m_currentIndex)
    39             {
    40                 return false;
    41             }
    42             args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize);
    43             m_currentIndex += m_bufferSize;
    44         }
    45         return true;
    46     }
    47 
    48     // Removes the buffer from a SocketAsyncEventArg object.  
    49     // This frees the buffer back to the buffer pool
    50     public void FreeBuffer(SocketAsyncEventArgs args)
    51     {
    52         m_freeIndexPool.Push(args.Offset);
    53         args.SetBuffer(null, 0, 0);
    54     }
    55 }
    View Code

    4.Server

      1 public class Server
      2 {
      3     private int m_numConnections;   // the maximum number of connections the sample is designed to handle simultaneously 
      4     private int m_receiveBufferSize;// buffer size to use for each socket I/O operation 
      5     BufferManager m_bufferManager;  // represents a large reusable set of buffers for all socket operations
      6     const int opsToPreAlloc = 2;    // read, write (don't alloc buffer space for accepts)
      7     Socket listenSocket;            // the socket used to listen for incoming connection requests
      8     // pool of reusable SocketAsyncEventArgs objects for write, read and accept socket operations
      9     SocketAsyncEventArgsPool m_readWritePool;
     10     int m_totalBytesRead;           // counter of the total # bytes received by the server
     11     int m_numConnectedSockets;      // the total number of clients connected to the server 
     12     Semaphore m_maxNumberAcceptedClients;
     13 
     14     // Create an uninitialized server instance.  
     15     // To start the server listening for connection requests
     16     // call the Init method followed by Start method 
     17     //
     18     // <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously</param>
     19     // <param name="receiveBufferSize">buffer size to use for each socket I/O operation</param>
     20     public Server(int numConnections, int receiveBufferSize)
     21     {
     22         m_totalBytesRead = 0;
     23         m_numConnectedSockets = 0;
     24         m_numConnections = numConnections;
     25         m_receiveBufferSize = receiveBufferSize;
     26         // allocate buffers such that the maximum number of sockets can have one outstanding read and 
     27         //write posted to the socket simultaneously  
     28         m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc,
     29             receiveBufferSize);
     30 
     31         m_readWritePool = new SocketAsyncEventArgsPool(numConnections);
     32         m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections);
     33     }
     34 
     35     // Initializes the server by preallocating reusable buffers and 
     36     // context objects.  These objects do not need to be preallocated 
     37     // or reused, but it is done this way to illustrate how the API can 
     38     // easily be used to create reusable objects to increase server performance.
     39     //
     40     public void Init()
     41     {
     42         // Allocates one large byte buffer which all I/O operations use a piece of.  This gaurds 
     43         // against memory fragmentation
     44         m_bufferManager.InitBuffer();
     45 
     46         // preallocate pool of SocketAsyncEventArgs objects
     47         SocketAsyncEventArgs readWriteEventArg;
     48 
     49         for (int i = 0; i < m_numConnections; i++)
     50         {
     51             //Pre-allocate a set of reusable SocketAsyncEventArgs
     52             readWriteEventArg = new SocketAsyncEventArgs();
     53             readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
     54             readWriteEventArg.UserToken = new AsyncUserToken();
     55 
     56             // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
     57             m_bufferManager.SetBuffer(readWriteEventArg);
     58 
     59             // add SocketAsyncEventArg to the pool
     60             m_readWritePool.Push(readWriteEventArg);
     61         }
     62 
     63     }
     64 
     65     // Starts the server such that it is listening for 
     66     // incoming connection requests.    
     67     //
     68     // <param name="localEndPoint">The endpoint which the server will listening 
     69     // for connection requests on</param>
     70     public void Start(IPEndPoint localEndPoint)
     71     {
     72         // create the socket which listens for incoming connections
     73         listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
     74         listenSocket.Bind(localEndPoint);
     75         // start the server with a listen backlog of 100 connections
     76         listenSocket.Listen(100);
     77 
     78         // post accepts on the listening socket
     79         StartAccept(null);
     80 
     81         //Console.WriteLine("{0} connected sockets with one outstanding receive posted to each....press any key", m_outstandingReadCount);
     82         Console.WriteLine("Press any key to terminate the server process....");
     83         Console.ReadKey();
     84     }
     85 
     86 
     87     // Begins an operation to accept a connection request from the client 
     88     //
     89     // <param name="acceptEventArg">The context object to use when issuing 
     90     // the accept operation on the server's listening socket</param>
     91     public void StartAccept(SocketAsyncEventArgs acceptEventArg)
     92     {
     93         if (acceptEventArg == null)
     94         {
     95             acceptEventArg = new SocketAsyncEventArgs();
     96             acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
     97         }
     98         else
     99         {
    100             // socket must be cleared since the context object is being reused
    101             acceptEventArg.AcceptSocket = null;
    102         }
    103 
    104         m_maxNumberAcceptedClients.WaitOne();
    105         bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);
    106         if (!willRaiseEvent)
    107         {
    108             ProcessAccept(acceptEventArg);
    109         }
    110     }
    111 
    112     // This method is the callback method associated with Socket.AcceptAsync 
    113     // operations and is invoked when an accept operation is complete
    114     //
    115     void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
    116     {
    117         ProcessAccept(e);
    118     }
    119 
    120     private void ProcessAccept(SocketAsyncEventArgs e)
    121     {
    122         Interlocked.Increment(ref m_numConnectedSockets);
    123         Console.WriteLine("Client connection accepted. There are {0} clients connected to the server",
    124             m_numConnectedSockets);
    125 
    126         // Get the socket for the accepted client connection and put it into the 
    127         //ReadEventArg object user token
    128         SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop();
    129         ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket;
    130 
    131         // As soon as the client is connected, post a receive to the connection
    132         bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
    133         if (!willRaiseEvent)
    134         {
    135             ProcessReceive(readEventArgs);
    136         }
    137 
    138         // Accept the next connection request
    139         StartAccept(e);
    140     }
    141 
    142     // This method is called whenever a receive or send operation is completed on a socket 
    143     //
    144     // <param name="e">SocketAsyncEventArg associated with the completed receive operation</param>
    145     void IO_Completed(object sender, SocketAsyncEventArgs e)
    146     {
    147         // determine which type of operation just completed and call the associated handler
    148         switch (e.LastOperation)
    149         {
    150             case SocketAsyncOperation.Receive:
    151                 ProcessReceive(e);
    152                 break;
    153             case SocketAsyncOperation.Send:
    154                 ProcessSend(e);
    155                 break;
    156             default:
    157                 throw new ArgumentException("The last operation completed on the socket was not a receive or send");
    158         }
    159     }
    160 
    161     // This method is invoked when an asynchronous receive operation completes. 
    162     // If the remote host closed the connection, then the socket is closed.  
    163     // If data was received then the data is echoed back to the client.
    164     //
    165     private void ProcessReceive(SocketAsyncEventArgs e)
    166     {
    167         // check if the remote host closed the connection
    168         AsyncUserToken token = (AsyncUserToken)e.UserToken;
    169         if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
    170         {
    171             //increment the count of the total bytes receive by the server
    172             Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred);
    173             Console.WriteLine("The server has read a total of {0} bytes", m_totalBytesRead);
    174 
    175             //echo the data received back to the client
    176             e.SetBuffer(e.Offset, e.BytesTransferred);
    177             bool willRaiseEvent = token.Socket.SendAsync(e);
    178             if (!willRaiseEvent)
    179             {
    180                 ProcessSend(e);
    181             }
    182 
    183         }
    184         else
    185         {
    186             CloseClientSocket(e);
    187         }
    188     }
    189 
    190     // This method is invoked when an asynchronous send operation completes.  
    191     // The method issues another receive on the socket to read any additional 
    192     // data sent from the client
    193     //
    194     // <param name="e"></param>
    195     private void ProcessSend(SocketAsyncEventArgs e)
    196     {
    197         if (e.SocketError == SocketError.Success)
    198         {
    199             // done echoing data back to the client
    200             AsyncUserToken token = (AsyncUserToken)e.UserToken;
    201             // read the next block of data send from the client
    202             bool willRaiseEvent = token.Socket.ReceiveAsync(e);
    203             if (!willRaiseEvent)
    204             {
    205                 ProcessReceive(e);
    206             }
    207         }
    208         else
    209         {
    210             CloseClientSocket(e);
    211         }
    212     }
    213 
    214     private void CloseClientSocket(SocketAsyncEventArgs e)
    215     {
    216         AsyncUserToken token = e.UserToken as AsyncUserToken;
    217 
    218         // close the socket associated with the client
    219         try
    220         {
    221             token.Socket.Shutdown(SocketShutdown.Send);
    222         }
    223         // throws if client process has already closed
    224         catch (Exception) { }
    225         token.Socket.Close();
    226 
    227         // decrement the counter keeping track of the total number of clients connected to the server
    228         Interlocked.Decrement(ref m_numConnectedSockets);
    229 
    230         // Free the SocketAsyncEventArg so they can be reused by another client
    231         m_readWritePool.Push(e);
    232 
    233         m_maxNumberAcceptedClients.Release();
    234         Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets);
    235     }
    236 }
    View Code

    1 class Program
    2 {
    3     static void Main(string[] args)
    4     {
    5         Server server = new Server(100, 1024);
    6         server.Init();
    7         server.Start(new IPEndPoint(IPAddress.Any, 8080));
    8     }
    9 }
  • 相关阅读:
    《Maven实战》文字版[PDF]
    spring管理的类如何调用非spring管理的类
    从session中获取当前用户的工具类
    WebService,ESB笔记
    Activiti
    ElasticSearch最全分词器比较及使用方法
    [ElasticSearch]Java API 之 滚动搜索(Scroll API)
    从html富文本中提取纯文本
    Jetty启动报Error scanning entry META-INF/versions/9/org/apache/logging/log4j/util/ProcessIdUtil.class
    elasticsearch: 创建mapping
  • 原文地址:https://www.cnblogs.com/linxmouse/p/11628573.html
Copyright © 2011-2022 走看看