使用完成端口(IOCP)
1 using System; 2 using System.Net; 3 using System.Net.Sockets; 4 5 namespace JCommon.Net 6 { 7 /// <summary> 8 /// 存储客户端信息, 这个可以根据自己的实际情况来定义 9 /// </summary> 10 public class AsyncUserToken 11 { 12 public IPEndPoint EndPort; 13 14 public Socket Socket; 15 16 /// <summary> 17 /// 连接时间 18 /// </summary> 19 public DateTime ConnectTime { get; set; } 20 } 21 }
1 using System; 2 using System.Collections.Generic; 3 using System.Net.Sockets; 4 5 namespace JCommon.Net 6 { 7 /// <summary> 8 /// 该类创建一个大缓冲区,该缓冲区可以分配给 SocketAsyncEventArgs 对象; 9 /// 这使bufffer易于重用,并能防止碎片化堆内存; 10 /// BufferManager 类的操作不是线程安全的。 11 /// </summary> 12 internal class BufferManager 13 { 14 private int m_numBytes; // 字节总数 15 private byte[] m_buffer; // 字节数组 16 private Stack<int> m_freeIndexPool; 17 private int m_currentIndex; 18 private int m_bufferSize; 19 20 public BufferManager(int totalBytes, int bufferSize) 21 { 22 this.m_numBytes = totalBytes; 23 this.m_currentIndex = 0; 24 this.m_bufferSize = bufferSize; 25 this.m_freeIndexPool = new Stack<int>(); 26 } 27 28 public void InitBuffer() 29 { 30 this.m_buffer = new byte[this.m_numBytes]; 31 } 32 33 /// <summary> 34 /// 将缓冲区分配给 SocketAsyncEventArgs 对象 35 /// </summary> 36 /// <param name="args"></param> 37 /// <returns></returns> 38 public bool SetBuffer(SocketAsyncEventArgs args) 39 { 40 if (this.m_freeIndexPool.Count > 0) 41 { 42 args.SetBuffer(this.m_buffer, this.m_freeIndexPool.Pop(), this.m_bufferSize); 43 } 44 else 45 { 46 if (this.m_numBytes - this.m_bufferSize < this.m_currentIndex) 47 { 48 return false; 49 } 50 args.SetBuffer(this.m_buffer, this.m_currentIndex, this.m_bufferSize); 51 this.m_currentIndex += this.m_bufferSize; 52 } 53 return true; 54 } 55 56 /// <summary> 57 /// 从 SocketAsyncEventArgs 对象回收缓冲区 58 /// </summary> 59 /// <param name="args"></param> 60 public void FreeBuffer(SocketAsyncEventArgs args) 61 { 62 this.m_freeIndexPool.Push(args.Offset); 63 args.SetBuffer(null, 0, 0); 64 } 65 } 66 }
1 using System; 2 using System.Collections.Generic; 3 using System.Net.Sockets; 4 5 namespace JCommon.Net 6 { 7 /// <summary> 8 /// 表示可重用SocketAsyncEventArgs对象的集合 9 /// </summary> 10 internal class SocketAsyncEventArgsPool 11 { 12 private Stack<SocketAsyncEventArgs> m_pool; 13 14 public SocketAsyncEventArgsPool(int capacity) 15 { 16 this.m_pool = new Stack<SocketAsyncEventArgs>(capacity); 17 } 18 19 public void Push(SocketAsyncEventArgs item) 20 { 21 if (item == null) 22 { 23 throw new ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); 24 } 25 lock (this.m_pool) 26 { 27 this.m_pool.Push(item); 28 } 29 } 30 31 public SocketAsyncEventArgs Pop() 32 { 33 SocketAsyncEventArgs result; 34 lock (this.m_pool) 35 { 36 result = this.m_pool.Pop(); 37 } 38 return result; 39 } 40 41 public int Count 42 { 43 get 44 { 45 return this.m_pool.Count; 46 } 47 } 48 } 49 }
1 using System; 2 using System.Net; 3 using System.Net.Sockets; 4 using System.Text; 5 using System.Threading; 6 7 namespace JCommon.Net 8 { 9 public class SocketClient 10 { 11 public event EventHandler<SocketAsyncEventArgs> OnReceived; 12 public event EventHandler<SocketAsyncEventArgs> OnSendCompleted; 13 public event EventHandler<SocketAsyncEventArgs> OnConnectCompleted; 14 public event EventHandler<SocketAsyncEventArgs> OnConnectionClosed; 15 16 private Socket sock; 17 private byte[] sendBuffer; 18 private int receiveBufferCapacity; 19 private int writeBufferCapacity; 20 private SocketAsyncEventArgs readArgs = new SocketAsyncEventArgs(); 21 private SocketAsyncEventArgs writeArgs = new SocketAsyncEventArgs(); 22 private SocketAsyncEventArgs connectArgs; 23 private AutoResetEvent sendCompletedEvent = new AutoResetEvent(false); 24 private object sync_disconn = new object(); 25 private byte[] receiveBuffer; 26 27 public SocketClient(int receiveCapacity = 1024, int sendCapacity = 256) 28 { 29 this.receiveBufferCapacity = receiveCapacity; 30 this.writeBufferCapacity = sendCapacity; 31 this.sock = new Socket(SocketType.Stream, ProtocolType.Tcp); 32 this.receiveBuffer = new byte[receiveCapacity]; 33 this.readArgs.SetBuffer(this.receiveBuffer, 0, receiveCapacity); 34 this.readArgs.Completed += this.IO_Completed; 35 this.readArgs.UserToken = new AsyncUserToken 36 { 37 Socket = this.sock 38 }; 39 this.sendBuffer = new byte[sendCapacity]; 40 this.writeArgs.SetBuffer(this.sendBuffer, 0, sendCapacity); 41 this.writeArgs.Completed += this.IO_Completed; 42 this.writeArgs.UserToken = new AsyncUserToken 43 { 44 Socket = this.sock 45 }; 46 } 47 48 ~SocketClient() 49 { 50 this.Disconnect(false); 51 } 52 53 public bool Connect(bool block = true) 54 { 55 if (this.sock != null && this.sock.Connected) 56 { 57 return true; 58 } 59 if (this.sock == null) 60 { 61 this.sock = new Socket(SocketType.Stream, ProtocolType.Tcp); 62 this.readArgs = new SocketAsyncEventArgs(); 63 this.readArgs.SetBuffer(this.receiveBuffer, 0, this.receiveBufferCapacity); 64 this.readArgs.Completed += this.IO_Completed; 65 this.readArgs.UserToken = new AsyncUserToken 66 { 67 Socket = this.sock 68 }; 69 this.writeArgs = new SocketAsyncEventArgs(); 70 this.writeArgs.SetBuffer(this.sendBuffer, 0, this.writeBufferCapacity); 71 this.writeArgs.Completed += this.IO_Completed; 72 this.writeArgs.UserToken = new AsyncUserToken 73 { 74 Socket = this.sock 75 }; 76 } 77 if (block) 78 { 79 this.sock.Connect(this.ServerIP, this.ServerPort); 80 if (this.sock.Connected) 81 { 82 // TCP客户端开始接受服务器发送的数据 83 this.readArgs.SetBuffer(0, this.receiveBufferCapacity); 84 if (!this.sock.ReceiveAsync(this.readArgs)) 85 { 86 this.ProcessReceive(this.readArgs); 87 } 88 } 89 } 90 else 91 { 92 this.connectArgs = new SocketAsyncEventArgs(); 93 this.connectArgs.Completed += this.IO_Completed; 94 this.connectArgs.UserToken = new AsyncUserToken 95 { 96 Socket = this.sock 97 }; 98 this.connectArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(this.ServerIP), this.ServerPort); 99 if (!this.sock.ConnectAsync(this.connectArgs)) 100 { 101 this.ProcessConnect(this.connectArgs); 102 } 103 } 104 return this.sock.Connected; 105 } 106 107 /// <summary> 108 /// 关闭连接 109 /// </summary> 110 /// <param name="reuseSocket">如果关闭套接字允许重用套接字则为true</param> 111 public void Disconnect(bool reuseSocket) 112 { 113 if (this.sock == null) 114 { 115 return; 116 } 117 if (this.sock.Connected) 118 { 119 try 120 { 121 lock (this.sync_disconn) 122 { 123 this.sock.Shutdown(SocketShutdown.Both); 124 this.sock.Disconnect(reuseSocket); 125 this.sock.Close(); 126 this.sock = null; 127 } 128 } 129 catch (SocketException) 130 { 131 this.sock = null; 132 } 133 catch (Exception) 134 { 135 this.sock = null; 136 } 137 } 138 } 139 140 public int Send(byte[] buffer) 141 { 142 if (this.sock == null || !this.sock.Connected) 143 { 144 return 0; 145 } 146 return this.sock.Send(buffer); 147 } 148 149 /// <summary> 150 /// 发送 151 /// </summary> 152 /// <param name="data">要发送的字符串</param> 153 /// <param name="bBlock">阻塞发送</param> 154 /// <returns></returns> 155 public int Send(string data, bool bBlock = true) 156 { 157 byte[] bytes = Encoding.Default.GetBytes(data); 158 if (bBlock) 159 { 160 return this.sock.Send(bytes); 161 } 162 if (bytes.Length > this.writeBufferCapacity) 163 { 164 this.writeBufferCapacity = bytes.Length; 165 this.sendBuffer = new byte[this.writeBufferCapacity]; 166 } 167 Array.Copy(bytes, this.sendBuffer, bytes.Length); 168 this.writeArgs.SetBuffer(0, bytes.Length); 169 if (!this.sock.SendAsync(this.writeArgs)) 170 { 171 this.ProcessSend(this.writeArgs); 172 } 173 return 0; 174 } 175 176 private void IO_Completed(object sender, SocketAsyncEventArgs e) 177 { 178 SocketAsyncOperation lastOperation = e.LastOperation; 179 switch (lastOperation) 180 { 181 case SocketAsyncOperation.Connect: 182 this.ProcessConnect(e); 183 return; 184 case SocketAsyncOperation.Disconnect: 185 break; 186 case SocketAsyncOperation.Receive: 187 this.ProcessReceive(e); 188 return; 189 default: 190 if (lastOperation == SocketAsyncOperation.Send) 191 { 192 this.ProcessSend(e); 193 return; 194 } 195 break; 196 } 197 throw new ArgumentException("The last operation completed on the socket was not a receive or send"); 198 } 199 200 /// <summary> 201 /// 处理接收到的数据 202 /// </summary> 203 /// <param name="e"></param> 204 private void ProcessReceive(SocketAsyncEventArgs e) 205 { 206 AsyncUserToken asyncUserToken = (AsyncUserToken)e.UserToken; 207 if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) 208 { 209 if (this.OnReceived != null) 210 { 211 this.OnReceived(this, e); 212 } 213 e.SetBuffer(e.Offset, this.receiveBufferCapacity); 214 if (!asyncUserToken.Socket.ReceiveAsync(e)) 215 { 216 this.ProcessReceive(e); 217 return; 218 } 219 } 220 else 221 { 222 this.CloseClientSocket(e); 223 } 224 } 225 226 /// <summary> 227 /// 发送完成后调用 228 /// </summary> 229 /// <param name="e"></param> 230 private void ProcessSend(SocketAsyncEventArgs e) 231 { 232 if (e.SocketError == SocketError.Success) 233 { 234 if (this.OnSendCompleted != null) 235 { 236 this.OnSendCompleted(this, e); 237 return; 238 } 239 } 240 else 241 { 242 this.CloseClientSocket(e); 243 } 244 } 245 246 private void ProcessConnect(SocketAsyncEventArgs e) 247 { 248 if (e.SocketError == SocketError.Success) 249 { 250 if (this.OnConnectCompleted != null) 251 { 252 this.OnConnectCompleted(this, e); 253 } 254 255 this.readArgs.SetBuffer(0, this.receiveBufferCapacity); 256 if (!this.sock.ReceiveAsync(this.readArgs)) 257 { 258 this.ProcessReceive(this.readArgs); 259 return; 260 } 261 } 262 else if (e.SocketError == SocketError.ConnectionRefused || e.SocketError == SocketError.HostUnreachable || e.SocketError == SocketError.TimedOut) 263 { 264 if (this.OnConnectCompleted != null) 265 { 266 this.OnConnectCompleted(this, e); 267 return; 268 } 269 } 270 else 271 { 272 this.CloseClientSocket(e); 273 } 274 } 275 276 private void CloseClientSocket(SocketAsyncEventArgs e) 277 { 278 if (this.OnConnectionClosed != null) 279 { 280 this.OnConnectionClosed(this, e); 281 } 282 AsyncUserToken asyncUserToken = e.UserToken as AsyncUserToken; 283 try 284 { 285 lock (this.sync_disconn) 286 { 287 if (this.sock != null) 288 { 289 this.sock.Shutdown(SocketShutdown.Send); 290 this.sock.Close(200); 291 this.sock = null; 292 } 293 } 294 } 295 catch (Exception){} 296 asyncUserToken.Socket = null; 297 } 298 299 private void Dispose() 300 { 301 try 302 { 303 // 关闭socket时,单独使用socket.close()通常会造成资源提前被释放, 304 // 应该在关闭socket之前,先使用shutdown进行接受或者发送的禁用,再使用socket进行释放 305 this.sock.Shutdown(SocketShutdown.Both); 306 this.sock.Close(); 307 this.sock.Dispose(); 308 this.sock = null; 309 } 310 catch (Exception){} 311 } 312 313 public string ServerIP { get; set; } 314 315 public int ServerPort { get; set; } 316 317 public byte[] ReceiveBuffer 318 { 319 get 320 { 321 return this.receiveBuffer; 322 } 323 } 324 325 public bool Connected 326 { 327 get 328 { 329 return this.sock != null && this.sock.Connected; 330 } 331 } 332 } 333 }
1 using System; 2 using System.Collections.Generic; 3 using System.Net; 4 using System.Net.Sockets; 5 using System.Threading; 6 7 namespace JCommon.Net 8 { 9 public class SocketServer 10 { 11 public event EventHandler<SocketAsyncEventArgs> OnReceiveCompleted; 12 public event EventHandler<SocketAsyncEventArgs> OnSendCompleted; 13 public event EventHandler<SocketAsyncEventArgs> OnAccept; 14 public event EventHandler<SocketAsyncEventArgs> OnConnectionBreak; 15 16 private const int opsToPreAlloc = 2; // 读,写(不为 接受连接 accepts 分配缓冲区空间) 17 private int m_numConnections; // 同时处理的最大连接数 18 private int m_receiveBufferSize; // 用于每个Socket I/O 操作的缓冲区大小 19 private BufferManager m_bufferManager; // 表示用于所有套接字操作的大量可重用的缓冲区 20 private Socket listenSocket; // 用于监听传入的连接请求的套接字 21 private SocketAsyncEventArgsPool m_readWritePool; // 可重用SocketAsyncEventArgs对象池,用于写入,读取和接受套接字操作 22 private List<SocketAsyncEventArgs> m_connectedPool; 23 private int m_totalBytesRead; // 服务器接收的总共#个字节的计数器 24 private int m_numConnectedSockets; // 连接到服务器的客户端总数 25 private Semaphore m_maxNumberAcceptedClients; 26 27 /// <summary> 28 /// 创建服务端实例 29 /// </summary> 30 /// <param name="numConnections"></param> 31 /// <param name="receiveBufferSize"></param> 32 public SocketServer(int numConnections, int receiveBufferSize) 33 { 34 this.m_totalBytesRead = 0; 35 this.m_numConnectedSockets = 0; 36 this.m_numConnections = numConnections; 37 this.m_receiveBufferSize = receiveBufferSize; 38 this.m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc, receiveBufferSize); 39 this.m_readWritePool = new SocketAsyncEventArgsPool(numConnections); 40 this.m_connectedPool = new List<SocketAsyncEventArgs>(numConnections); 41 } 42 43 /// <summary> 44 /// 分配 SocketAsyncEventArg 对象池 45 /// </summary> 46 public void Init() 47 { 48 // 分配一个大字节缓冲区,所有 I/O 操作都使用该缓冲区。 49 this.m_bufferManager.InitBuffer(); 50 for (int i = 0; i < this.m_numConnections; i++) 51 { 52 // 分配可重用的 SocketAsyncEventArgs 对象 53 SocketAsyncEventArgs socketAsyncEventArgs = new SocketAsyncEventArgs(); 54 socketAsyncEventArgs.Completed += this.IO_Completed; 55 socketAsyncEventArgs.UserToken = new AsyncUserToken(); 56 57 // 将缓冲池中的字节缓冲区分配给 SocketAsyncEventArg 对象 58 this.m_bufferManager.SetBuffer(socketAsyncEventArgs); 59 60 // 放入对象池 61 this.m_readWritePool.Push(socketAsyncEventArgs); 62 } 63 } 64 65 /// <summary> 66 /// 启动服务器,侦听客户端连接请求 67 /// </summary> 68 /// <param name="localEndPoint"></param> 69 public void Start(IPEndPoint localEndPoint) 70 { 71 try 72 { 73 // 限制最大连接数 74 this.m_maxNumberAcceptedClients = new Semaphore(this.m_numConnections, this.m_numConnections); 75 76 // 创建 Socket 监听连接请求 77 this.listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 78 this.listenSocket.Bind(localEndPoint); 79 this.listenSocket.Listen(10); 80 81 // 接受客户端连接请求 82 this.StartAccept(null); 83 } 84 catch (Exception){} 85 } 86 87 public void Stop() 88 { 89 if (this.listenSocket == null) 90 { 91 return; 92 } 93 try 94 { 95 lock(m_connectedPool) 96 { 97 for (int i = 0; i < this.m_connectedPool.Count; i++) 98 { 99 this.CloseClientSocket(m_connectedPool[i]); 100 } 101 this.m_connectedPool.Clear(); 102 } 103 this.listenSocket.LingerState = new LingerOption(true, 0); 104 this.listenSocket.Close(); 105 this.listenSocket.Dispose(); 106 this.listenSocket = null; 107 GC.Collect(); 108 } 109 catch (Exception) 110 { 111 } 112 } 113 114 public void Send(AsyncUserToken arg, byte[] msg) 115 { 116 SocketAsyncEventArgs argSend = this.m_connectedPool.Find((s) => { 117 AsyncUserToken userToken = s.UserToken as AsyncUserToken; 118 return userToken.EndPort.ToString() == arg.EndPort.ToString(); 119 }); 120 121 AsyncUserToken userToken1 = argSend.UserToken as AsyncUserToken; 122 userToken1.Socket.Send(msg); 123 } 124 125 public void SendToAll(byte[] msg) 126 { 127 foreach(SocketAsyncEventArgs arg in this.m_connectedPool) 128 { 129 AsyncUserToken userToken = arg.UserToken as AsyncUserToken; 130 userToken.Socket.Send(msg); 131 } 132 } 133 134 /// <summary> 135 /// 开始接受来自客户端的连接请求 136 /// </summary> 137 /// <param name="acceptEventArg"></param> 138 private void StartAccept(SocketAsyncEventArgs acceptEventArg) 139 { 140 if (acceptEventArg == null) 141 { 142 acceptEventArg = new SocketAsyncEventArgs(); 143 acceptEventArg.Completed += this.AcceptEventArg_Completed; 144 } 145 else 146 { 147 acceptEventArg.AcceptSocket = null; 148 } 149 this.m_maxNumberAcceptedClients.WaitOne(); 150 if (this.listenSocket == null) 151 { 152 return; 153 } 154 if (!this.listenSocket.AcceptAsync(acceptEventArg)) 155 { 156 this.ProcessAccept(acceptEventArg); 157 } 158 } 159 160 /// <summary> 161 /// 接受连接请求完成后回调 162 /// </summary> 163 /// <param name="sender"></param> 164 /// <param name="e"></param> 165 private void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) 166 { 167 this.ProcessAccept(e); 168 } 169 170 private void ProcessAccept(SocketAsyncEventArgs e) 171 { 172 if (e.SocketError == SocketError.Success) 173 { 174 Interlocked.Increment(ref this.m_numConnectedSockets); 175 if (this.OnAccept != null) 176 { 177 this.OnAccept(null, e); 178 } 179 180 // 获取接受的客户端连接的套接字 181 SocketAsyncEventArgs socketAsyncEventArgs = this.m_readWritePool.Pop(); 182 AsyncUserToken userToken = socketAsyncEventArgs.UserToken as AsyncUserToken; 183 userToken.Socket = e.AcceptSocket; 184 userToken.ConnectTime = DateTime.Now; 185 userToken.EndPort = e.AcceptSocket.RemoteEndPoint as IPEndPoint; 186 187 lock (m_connectedPool) 188 { 189 this.m_connectedPool.Add(socketAsyncEventArgs); 190 } 191 192 if (!e.AcceptSocket.ReceiveAsync(socketAsyncEventArgs)) 193 { 194 this.ProcessReceive(socketAsyncEventArgs); 195 } 196 197 // 接受下一个连接请求 198 this.StartAccept(e); 199 } 200 else 201 { 202 this.Stop(); 203 } 204 } 205 206 /// <summary> 207 /// 每当套接字上的接收或发送操作完成时,就会调用此方法 208 /// </summary> 209 /// <param name="sender"></param> 210 /// <param name="e"></param> 211 private void IO_Completed(object sender, SocketAsyncEventArgs e) 212 { 213 switch (e.LastOperation) 214 { 215 case SocketAsyncOperation.Receive: 216 ProcessReceive(e); 217 break; 218 case SocketAsyncOperation.Send: 219 ProcessSend(e); 220 break; 221 default: 222 throw new ArgumentException("The last operation completed on the socket was not a receive or send"); 223 } 224 } 225 226 /// <summary> 227 /// 异步接收操作完成后,将调用此方法。 228 /// </summary> 229 /// <param name="e"></param> 230 private void ProcessReceive(SocketAsyncEventArgs e) 231 { 232 AsyncUserToken asyncUserToken = (AsyncUserToken)e.UserToken; 233 if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) 234 { 235 Interlocked.Add(ref this.m_totalBytesRead, e.BytesTransferred); 236 if (this.OnReceiveCompleted != null) 237 { 238 this.OnReceiveCompleted(this, e); 239 } 240 e.SetBuffer(e.Offset, this.m_receiveBufferSize); 241 if (!asyncUserToken.Socket.ReceiveAsync(e)) 242 { 243 this.ProcessReceive(e); 244 return; 245 } 246 } 247 else 248 { 249 this.CloseClientSocket(e); 250 } 251 } 252 253 /// <summary> 254 /// 异步发送操作完成后,将调用此方法。 255 /// 该方法在套接字上发出另一个接收,以读取从客户端发送的所有其他数据 256 /// </summary> 257 /// <param name="e"></param> 258 private void ProcessSend(SocketAsyncEventArgs e) 259 { 260 if (e.SocketError == SocketError.Success) 261 { 262 if (this.OnSendCompleted != null) 263 { 264 this.OnSendCompleted(null, e); 265 } 266 AsyncUserToken asyncUserToken = (AsyncUserToken)e.UserToken; 267 if (!asyncUserToken.Socket.ReceiveAsync(e)) 268 { 269 this.ProcessReceive(e); 270 return; 271 } 272 } 273 else 274 { 275 this.CloseClientSocket(e); 276 } 277 } 278 279 private void CloseClientSocket(SocketAsyncEventArgs e) 280 { 281 if (this.OnConnectionBreak != null) 282 { 283 this.OnConnectionBreak(null, e); 284 } 285 AsyncUserToken asyncUserToken = e.UserToken as AsyncUserToken; 286 if (asyncUserToken != null && asyncUserToken.Socket != null) 287 { 288 try 289 { 290 asyncUserToken.Socket.Shutdown(SocketShutdown.Both); 291 asyncUserToken.Socket.Disconnect(false); 292 asyncUserToken.Socket.Close(); 293 asyncUserToken.Socket = null; 294 } 295 catch (Exception) 296 { 297 } 298 finally 299 { 300 Interlocked.Decrement(ref this.m_numConnectedSockets); 301 this.m_maxNumberAcceptedClients.Release(); 302 this.m_readWritePool.Push(e); 303 lock (m_connectedPool) 304 { 305 this.m_connectedPool.Remove(e); 306 } 307 } 308 } 309 } 310 } 311 }