• 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 }
  • 相关阅读:
    前端好用js库
    springmvc 配置之 mvc:default-servlet-handler
    springmvc配置之mvc:annotation-driven
    spring mvc 配置之 context:annotation-config vs component-scan
    React 学习笔记
    数据结构乱写
    字符串乱写
    HEOI2020 游记
    奇怪的基础容斥数学课件
    省选模拟104 题解
  • 原文地址:https://www.cnblogs.com/jshchg/p/12931644.html
Copyright © 2020-2023  润新知