1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Security.Cryptography;
5 using System.Net.Sockets;
6 using System.Net;
7 using System.IO;
8 using System.Threading;
9
10 namespace XuanJiSocket
11 {
12 /// <summary>
13 /// ClassName 玄机SocketHelper
14 /// Coding By 君临
15 /// </summary>
16 public class SocketHelper
17 {
18 #region 推送器
19 public delegate void PushSockets(Sockets sockets);
20 public static PushSockets pushSockets;
21 #endregion
22 /// <summary>
23 /// Tcp同步服务端,SocketObject继承抽象类
24 /// 服务端采用TcpListener封装.
25 /// 使用Semaphore 来控制并发,每次处理5个.最大处理5000
26 /// </summary>
27 public class TcpServer : SocketObject
28 {
29 bool IsStop = false;
30 object obj = new object();
31 /// <summary>
32 /// 信号量
33 /// </summary>
34 private Semaphore semap = new Semaphore(5, 5000);
35 /// <summary>
36 /// 客户端队列集合
37 /// </summary>
38 public List<Sockets> ClientList = new List<Sockets>();
39 /// <summary>
40 /// 服务端
41 /// </summary>
42 private TcpListener listener;
43 /// <summary>
44 /// 当前IP地址
45 /// </summary>
46 private IPAddress Ipaddress;
47 /// <summary>
48 /// 欢迎消息
49 /// </summary>
50 private string boundary = "www.xuanjics.com";
51 /// <summary>
52 /// 当前监听端口
53 /// </summary>
54 private int Port;
55 /// <summary>
56 /// 当前IP,端口对象
57 /// </summary>
58 private IPEndPoint ip;
59 /// <summary>
60 /// 初始化服务端对象
61 /// </summary>
62 /// <param name="ipaddress">IP地址</param>
63 /// <param name="port">监听端口</param>
64 public override void InitSocket(IPAddress ipaddress, int port)
65 {
66 Ipaddress = ipaddress;
67 Port = port;
68 listener = new TcpListener(Ipaddress, Port);
69 }
70 /// <summary>
71 /// 初始化服务端对象
72 /// </summary>
73 /// <param name="ipaddress">IP地址</param>
74 /// <param name="port">监听端口</param>
75 public override void InitSocket(string ipaddress, int port)
76 {
77 Ipaddress = IPAddress.Parse(ipaddress);
78 Port = port;
79 ip = new IPEndPoint(Ipaddress, Port);
80 listener = new TcpListener(Ipaddress, Port);
81 }
82 /// <summary>
83 /// 启动监听,并处理连接
84 /// </summary>
85 public override void Start()
86 {
87 try
88 {
89 listener.Start();
90 Thread AccTh = new Thread(new ThreadStart(delegate
91 {
92 while (true)
93 {
94
95 if (IsStop != false)
96 {
97 break;
98 }
99 GetAcceptTcpClient();
100 Thread.Sleep(1);
101 }
102 }));
103 AccTh.Start();
104 }
105 catch (SocketException skex)
106 {
107 Sockets sks = new Sockets();
108 sks.ex = skex;
109 pushSockets.Invoke(sks);//推送至UI
110
111 }
112 }
113 /// <summary>
114 /// 等待处理新的连接
115 /// </summary>
116 private void GetAcceptTcpClient()
117 {
118 try
119 {
120 if (listener.Pending())
121 {
122 semap.WaitOne();
123 TcpClient tclient = listener.AcceptTcpClient();
124 //维护客户端队列
125 Socket socket = tclient.Client;
126 NetworkStream stream = new NetworkStream(socket, true); //承载这个Socket
127 Sockets sks = new Sockets(tclient.Client.RemoteEndPoint as IPEndPoint, tclient, stream);
128 sks.NewClientFlag = true;
129 //推送新客户端
130 pushSockets.Invoke(sks);
131 //客户端异步接收
132 sks.nStream.BeginRead(sks.RecBuffer, 0, sks.RecBuffer.Length, new AsyncCallback(EndReader), sks);
133 //加入客户端集合.
134 AddClientList(sks);
135 //主动向客户端发送一条连接成功信息
136 if (stream.CanWrite)
137 {
138 byte[] buffer = Encoding.UTF8.GetBytes(boundary);
139 stream.Write(buffer, 0, buffer.Length);
140 }
141 semap.Release();
142 }
143 }
144 catch
145 {
146 return;
147 }
148 }
149 /// <summary>
150 /// 异步接收发送的信息.
151 /// </summary>
152 /// <param name="ir"></param>
153 private void EndReader(IAsyncResult ir)
154 {
155 Sockets sks = ir.AsyncState as Sockets;
156
157
158 if (sks != null && listener != null)
159 {
160 try
161 {
162 if (sks.NewClientFlag || sks.Offset != 0)
163 {
164 sks.NewClientFlag = false;
165 sks.Offset = sks.nStream.EndRead(ir);
166 pushSockets.Invoke(sks);//推送至UI
167 sks.nStream.BeginRead(sks.RecBuffer, 0, sks.RecBuffer.Length, new AsyncCallback(EndReader), sks);
168 }
169 }
170 catch (Exception skex)
171 {
172 lock (obj)
173 {
174 //移除异常类
175 ClientList.Remove(sks);
176 Sockets sk = sks;
177 sk.ClientDispose = true;//客户端退出
178 sk.ex = skex;
179 pushSockets.Invoke(sks);//推送至UI
180 }
181 }
182 }
183 }
184 /// <summary>
185 /// 加入队列.
186 /// </summary>
187 /// <param name="sk"></param>
188 private void AddClientList(Sockets sk)
189 {
190 //虽然有信号量,还是用lock增加系数
191 lock (obj)
192 {
193 Sockets sockets = ClientList.Find(o => { return o.Ip == sk.Ip; });
194 //如果不存在则添加,否则更新
195 if (sockets == null)
196 {
197 ClientList.Add(sk);
198 }
199 else
200 {
201 ClientList.Remove(sockets);
202 ClientList.Add(sk);
203 }
204 }
205 }
206 public override void Stop()
207 {
208 if (listener != null)
209 {
210 listener.Stop();
211 listener = null;
212 IsStop = true;
213 SocketHelper.pushSockets = null;
214 }
215 }
216 /// <summary>
217 /// 向所有在线的客户端发送信息.
218 /// </summary>
219 /// <param name="SendData">发送的文本</param>
220 public void SendToAll(string SendData)
221 {
222 for (int i = 0; i < ClientList.Count; i++)
223 {
224 SendToClient(ClientList[i].Ip, SendData);
225 }
226 }
227 /// <summary>
228 /// 向某一位客户端发送信息
229 /// </summary>
230 /// <param name="ip">客户端IP+端口地址</param>
231 /// <param name="SendData">发送的数据包</param>
232 public void SendToClient(IPEndPoint ip, string SendData)
233 {
234 try
235 {
236 Sockets sks = ClientList.Find(o => { return o.Ip == ip; });
237 if (sks == null || !sks.Client.Connected)
238 {
239 //没有连接时,标识退出
240 Sockets ks = new Sockets();
241 sks.ClientDispose = true;//标识客户端下线
242 sks.ex = new Exception("客户端无连接");
243 pushSockets.Invoke(sks);//推送至UI
244 }
245 if (sks.Client.Connected)
246 {
247 //获取当前流进行写入.
248 NetworkStream nStream = sks.nStream;
249 if (nStream.CanWrite)
250 {
251 byte[] buffer = Encoding.UTF8.GetBytes(SendData);
252 nStream.Write(buffer, 0, buffer.Length);
253 }
254 else
255 {
256 //避免流被关闭,重新从对象中获取流
257 nStream = sks.Client.GetStream();
258 if (nStream.CanWrite)
259 {
260 byte[] buffer = Encoding.UTF8.GetBytes(SendData);
261 nStream.Write(buffer, 0, buffer.Length);
262 }
263 else
264 {
265 //如果还是无法写入,那么认为客户端中断连接.
266 ClientList.Remove(sks);
267 Sockets ks = new Sockets();
268 sks.ClientDispose = true;//如果出现异常,标识客户端下线
269 sks.ex = new Exception("客户端无连接");
270 pushSockets.Invoke(sks);//推送至UI
271
272 }
273 }
274 }
275 }
276 catch (Exception skex)
277 {
278 Sockets sks = new Sockets();
279 sks.ClientDispose = true;//如果出现异常,标识客户端退出
280 sks.ex = skex;
281 pushSockets.Invoke(sks);//推送至UI
282
283 }
284 }
285 }
286 public class TcpClients : SocketObject
287 {
288 bool IsClose = false;
289 /// <summary>
290 /// 当前管理对象
291 /// </summary>
292 Sockets sk;
293 /// <summary>
294 /// 客户端
295 /// </summary>
296 TcpClient client;
297 /// <summary>
298 /// 当前连接服务端地址
299 /// </summary>
300 IPAddress Ipaddress;
301 /// <summary>
302 /// 当前连接服务端端口号
303 /// </summary>
304 int Port;
305 /// <summary>
306 /// 服务端IP+端口
307 /// </summary>
308 IPEndPoint ip;
309 /// <summary>
310 /// 发送与接收使用的流
311 /// </summary>
312 NetworkStream nStream;
313 /// <summary>
314 /// 初始化Socket
315 /// </summary>
316 /// <param name="ipaddress"></param>
317 /// <param name="port"></param>
318 public override void InitSocket(string ipaddress, int port)
319 {
320 Ipaddress = IPAddress.Parse(ipaddress);
321 Port = port;
322 ip = new IPEndPoint(Ipaddress, Port);
323 client = new TcpClient();
324 }
325 public void SendData(string SendData)
326 {
327 try
328 {
329
330 if (client == null || !client.Connected)
331 {
332 Sockets sks = new Sockets();
333 sks.ex = new Exception("客户端无连接..");
334 sks.ClientDispose = true;
335 pushSockets.Invoke(sks);//推送至UI
336 }
337 if (client.Connected) //如果连接则发送
338 {
339 if (nStream == null)
340 {
341 nStream = client.GetStream();
342 }
343 byte[] buffer = Encoding.UTF8.GetBytes(SendData);
344 nStream.Write(buffer, 0, buffer.Length);
345 }
346 }
347 catch (Exception skex)
348 {
349 Sockets sks = new Sockets();
350 sks.ex = skex;
351 sks.ClientDispose = true;
352 pushSockets.Invoke(sks);//推送至UI
353 }
354 }
355 /// <summary>
356 /// 初始化Socket
357 /// </summary>
358 /// <param name="ipaddress"></param>
359 /// <param name="port"></param>
360 public override void InitSocket(IPAddress ipaddress, int port)
361 {
362 Ipaddress = ipaddress;
363 Port = port;
364 ip = new IPEndPoint(Ipaddress, Port);
365 client = new TcpClient();
366 }
367 private void Connect()
368 {
369 client.Connect(ip);
370 nStream = new NetworkStream(client.Client, true);
371 sk = new Sockets(ip, client, nStream);
372 sk.nStream.BeginRead(sk.RecBuffer, 0, sk.RecBuffer.Length, new AsyncCallback(EndReader), sk);
373 }
374 private void EndReader(IAsyncResult ir)
375 {
376
377 Sockets s = ir.AsyncState as Sockets;
378 try
379 {
380 if (s != null)
381 {
382
383 if (IsClose && client == null)
384 {
385 sk.nStream.Close();
386 sk.nStream.Dispose();
387 return;
388 }
389 s.Offset = s.nStream.EndRead(ir);
390 pushSockets.Invoke(s);//推送至UI
391 sk.nStream.BeginRead(sk.RecBuffer, 0, sk.RecBuffer.Length, new AsyncCallback(EndReader), sk);
392 }
393 }
394 catch (Exception skex)
395 {
396 Sockets sks = s;
397 sks.ex = skex;
398 sks.ClientDispose = true;
399 pushSockets.Invoke(sks);//推送至UI
400
401 }
402
403 }
404 /// <summary>
405 /// 重写Start方法,其实就是连接服务端
406 /// </summary>
407 public override void Start()
408 {
409 Connect();
410 }
411 public override void Stop()
412 {
413 Sockets sks = new Sockets();
414 if (client != null)
415 {
416 client.Client.Shutdown(SocketShutdown.Both);
417 Thread.Sleep(10);
418 client.Close();
419 IsClose = true;
420 client = null;
421 }
422 else
423 {
424 sks.ex = new Exception("客户端没有初始化.!");
425 }
426 pushSockets.Invoke(sks);//推送至UI
427 }
428
429 }
430 /// <summary>
431 /// Socket基类(抽象类)
432 /// 抽象3个方法,初始化Socket(含一个构造),停止,启动方法.
433 /// 此抽象类为TcpServer与TcpClient的基类,前者实现后者抽象方法.
434 /// 作用: 纯属闲的蛋疼,不写个OO的我感觉不会写代码了...What The Fuck...
435 /// </summary>
436 public abstract class SocketObject
437 {
438 public abstract void InitSocket(IPAddress ipaddress, int port);
439 public abstract void InitSocket(string ipaddress, int port);
440 public abstract void Start();
441 public abstract void Stop();
442 }
443 /// <summary>
444 /// 自定义Socket对象
445 /// </summary>
446 public class Sockets
447 {
448 /// <summary>
449 /// 接收缓冲区
450 /// </summary>
451 public byte[] RecBuffer = new byte[8 * 1024];
452 /// <summary>
453 /// 发送缓冲区
454 /// </summary>
455 public byte[] SendBuffer = new byte[8 * 1024];
456 /// <summary>
457 /// 异步接收后包的大小
458 /// </summary>
459 public int Offset { get; set; }
460 /// <summary>
461 /// 空构造
462 /// </summary>
463 public Sockets() { }
464 /// <summary>
465 /// 创建Sockets对象
466 /// </summary>
467 /// <param name="ip">Ip地址</param>
468 /// <param name="client">TcpClient</param>
469 /// <param name="ns">承载客户端Socket的网络流</param>
470 public Sockets(IPEndPoint ip, TcpClient client, NetworkStream ns)
471 {
472 Ip = ip;
473 Client = client;
474 nStream = ns;
475 }
476 /// <summary>
477 /// 当前IP地址,端口号
478 /// </summary>
479 public IPEndPoint Ip { get; set; }
480 /// <summary>
481 /// 客户端主通信程序
482 /// </summary>
483 public TcpClient Client { get; set; }
484 /// <summary>
485 /// 承载客户端Socket的网络流
486 /// </summary>
487 public NetworkStream nStream { get; set; }
488 /// <summary>
489 /// 发生异常时不为null.
490 /// </summary>
491 public Exception ex { get; set; }
492 /// <summary>
493 /// 新客户端标识.如果推送器发现此标识为true,那么认为是客户端上线
494 /// 仅服务端有效
495 /// </summary>
496 public bool NewClientFlag { get; set; }
497 /// <summary>
498 /// 客户端退出标识.如果服务端发现此标识为true,那么认为客户端下线
499 /// 客户端接收此标识时,认为客户端异常.
500 /// </summary>
501 public bool ClientDispose { get; set; }
502 }
503 }
504 }