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 }

 

posted @ 2019-10-06 21:36  非法关键字  阅读(431)  评论(0编辑  收藏  举报