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 }