TcpListener、TcpClient 、NetworkStream

  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 }

 

posted on 2020-05-21 16:33  jshchg  阅读(367)  评论(0编辑  收藏  举报

导航