歡迎您的來訪!有源碼,好建站(m.bmm520.net)源碼海洋源碼網為您提供快速建站平臺.
      當前位置: 首頁 > 行業資訊 > c# .net 資料 >

      C#實現TCP客戶端,可檢測斷線并自動重連保持連接,對于網線斷開或拔掉的情況也可檢測到

      時間:2021-07-11 23:39來源:未知 作者:admin 點擊:
      使用C#實現的TCP客戶端,可檢測斷線(包括網線斷開或拔掉),支持斷線重連?蛻舳藘炔坑醒h緩沖區異步接收數據,對客戶端的讀操作會立即返回,根據方法返回值來判斷讀取數據的字節數。 對外提供3個事件分別是: 收到數據事件(網絡收到數據觸發此事件) 通訊空

       使用C#實現的TCP客戶端,可檢測斷線(包括網線斷開或拔掉),支持斷線重連。客戶端內部有循環緩沖區異步接收數據,對客戶端的讀操作會立即返回,根據方法返回值來判斷讀取數據的字節數。

       
      對外提供3個事件分別是:
       
          收到數據事件(網絡收到數據觸發此事件)
          通訊空閑事件(長時間無數據收發,時間可設)
          重連失敗事件(默認最大支持3次重連,若3次重連仍然失敗則觸發事件)
       
      使用方式:
      private Thread _socketThread;
      private TcpClient _client;
       
      _socketThread = new Thread(_client.ReadFormSocket);
      _socketThread.IsBackground = false;
      _socketThread.Start();
       
      //接收數據操作,除此之外還可以注冊接收事件,有數據來時讀取
      byte [] recv = new byte[100];
      _client.CommReceive(recv,100);
       
      //發送數據
      byte [] send = new byte[10];
      for (int i = 0; i < 10; i++)
          send[i] = i;
      _client.CommSend(send,10);
      ————————————————
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Net.Sockets;
      using System.Net;
      using System.Timers;
       
      namespace Communication
      {
          //通訊接口事件代理
          internal delegate void CommRxEventHandler();
          internal delegate void CommIdleEventHandler();
       
          //通訊接口
          internal interface ICommunication
          {
              event CommRxEventHandler CommRxEvent;       //收到數據事件
              event CommIdleEventHandler CommIdleEvent;   //通訊空閑事件
       
              int CommSend(byte[] buffer, int size);      //發送數據到通訊口
              int CommReceive(CommBuffer buffer);         //從通訊口接收數據
              int CommReceive(byte[] buffer, int size);   //從通訊口接收數據
          }
       
          //TCP客戶端實現
          internal class TcpClient : ICommunication
          {
              private const int MAX_RECONNECT_TIMES = 3;  //斷線重連嘗試次數
              private const int COMM_IDLE_TIMES = 3;      //通訊空閑觸發間隔
       
              //soket對象及參數
              private Socket _socket;     
              private string _host;       
              private int _port;
              private bool _reconnect;
              private int ConnecteFailedCount { get; set; }
              public int ReconnectStatistics { get; private set; } 
       
              private static uint _keepAliveTime = 5000;      //無數據交互持續時間(ms)
              private static uint _keepAliveInterval = 500;   //發送探測包間隔(ms)
       
              //定時器,用于觸發通訊空閑
              private Timer _timer;
              private int _commIdleCount;
       
              //實現接口的兩個事件
              public event CommRxEventHandler CommRxEvent;
              public event CommIdleEventHandler CommIdleEvent;
       
              //重連失敗事件
              public event EventHandler ReconnectionFailedEvent;
       
              //數據接收緩存
              private CommBuffer recvBuffer;
       
              //構造函數
              public TcpClient(string host,int port)
              {
                  _host = host;
                  _port = port;
                  _reconnect = false;
                  ConnecteFailedCount = 0;
                  recvBuffer = new CommBuffer(20480);
              }
              
              //連接
              public void Connect()
              {
                  _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                      ProtocolType.Tcp);
                  _socket.Connect(_host, _port);
                  ConnecteFailedCount = MAX_RECONNECT_TIMES;
       
                  //設置KeepAlive
                  _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                  byte[] optionValue = new byte[12];
                  BitConverter.GetBytes(1).CopyTo(optionValue, 0);
                  BitConverter.GetBytes(_keepAliveTime).CopyTo(optionValue, 4);
                  BitConverter.GetBytes(_keepAliveInterval).CopyTo(optionValue, 8);
                  _socket.IOControl(IOControlCode.KeepAliveValues, optionValue, null);
              }
       
              //重連
              public bool Reconnect()
              {
                  ReconnectStatistics++;
                  _reconnect = false;
                  Close();
                  try
                  {
                      Connect();
                  }
                  catch (SocketException e)
                  {
                      ConnecteFailedCount--;
                      if (ConnecteFailedCount > 0)
                      {
                          //Console.WriteLine("重試次數剩余{0}",ConnecteFailedCount);
                          _reconnect = true;
                          return true;
                      }
                      else
                      {
                          //重連失敗事件
                          if (ReconnectionFailedEvent != null)
                              ReconnectionFailedEvent(this, new EventArgs());
                          return false;
                      }
                  }
                  return true;
              }
       
              //釋放資源
              public void Close()
              {
                  _socket.Close();
              }
       
              //啟動空閑事件觸發
              public void StartCommIdle()
              {
                  //定時器配置
                  _timer = new Timer(500);
                  _timer.AutoReset = true;
                  _timer.Elapsed += TimerElapsed;
                  _timer.Start();
                  _commIdleCount = 0;
              }
              
              //停止空閑事件觸發
              public void StopCommIdle()
              {
                  _timer.Elapsed -= TimerElapsed;
                  _timer.Close();
              }
       
              //發送接收數據事件
              public void SendRecvEvent()
              {
                  if (CommRxEvent != null)
                      CommRxEvent();
              }
       
              //發送超時事件
              public void TimerElapsed(object sender, ElapsedEventArgs e)
              {
                  if (_commIdleCount++ >= COMM_IDLE_TIMES)
                  {
                      if (CommIdleEvent != null)
                          CommIdleEvent();
                      _commIdleCount = 0;
                  }
              }
       
              //發送數據接收實現,斷線重連
              public int CommSend(byte[] buffer, int size)
              {
                  int sendSize = 0;
                  try 
                  {
                      sendSize = _socket.Send(buffer, size, SocketFlags.None);
                      _commIdleCount = 0;
                  }
                  catch (SocketException e)
                  {
                      ReconnectStatistics++;
                      _reconnect = true;
                  }
                  return sendSize;
              }
       
              //接收數據接口實現
              public int CommReceive(byte[] buffer, int size)
              {
                  return recvBuffer.Read(buffer, size);
              }
       
              //接收數據接口實現
              public int CommReceive(CommBuffer buffer)
              {
                  return recvBuffer.CopyTo(buffer);
              }
       
              //接收數據線程,使用阻塞方式接收數據
              public void ReadFormSocket()
              {
                  int recvNum;
                  byte[] recv = new byte[2048];
                  while(true)
                  {
                      try
                      {
                          recvNum = _socket.Receive(recv, SocketFlags.None);
                      }
                      catch(SocketException e)
                      {
                          recvNum = 0;
                      }
       
                      //網絡斷開Receive返回0
                      if (recvNum == 0 || _reconnect == true)
                      {
                          //重連次數用盡,退出
                          if (Reconnect() == false)
                              break;
                      }
                      else
                      {
                          recvBuffer.Write(recv, recvNum);
                          SendRecvEvent();
                      }
                      _commIdleCount = 0;
                  }
              }
          }
       
          //通訊緩沖結構類
          internal class CommBuffer
          {
              public uint capacity;              //緩沖區大小
              public int readPtr;                //讀指針
              public int writePtr;               //寫指針
              public byte[] pBuf;                //緩沖區
       
              //構造函數
              public CommBuffer(uint capacity)
              {
                  this.capacity = capacity;
                  this.readPtr = 0;
                  this.writePtr = 0;
                  this.pBuf = new byte[capacity];
              }
       
              //從緩沖區中讀取數據到byte數組
              public int Read(byte[] buff, int size)
              {
                  int readSize;
                  for (readSize = 0; readSize < size; readSize++)
                  {
                      if (IsEmpty())
                          break;
                      buff[readSize] = pBuf[readPtr++];
                      if (readPtr >= capacity)
                          readPtr = 0;
                  }
                  return readSize;
              }
       
              //將byte數組寫入緩沖區
              public int Write(byte[] buff, int size)
              {
                  int writeSize, wp;
                  for (writeSize = 0; writeSize < size; writeSize++)
                  {
                      wp = writePtr + 1;
                      if (wp >= capacity)
                          wp = 0;
                      if (wp == readPtr)
                          break;
                      pBuf[writePtr] = buff[writeSize];
                      writePtr = wp;
       
                  }
                  return writeSize;
              }
       
              //拷貝buffer緩沖區數據到本緩沖區內,會引起拷貝源有效數據為空
              public int Copy(CommBuffer buffer, int len)
              {
                  if (len == 0)
                      return 0;
                  byte[] data = new byte[len];
                  len = buffer.Read(data, len);
                  return this.Write(data, len);
              }
       
              //拷貝本緩沖區中的數據到buffer中,會引起拷貝源有效數據為空
              public int CopyTo(CommBuffer buffer)
              {
                  int dataLen = this.DataLength();
                  if (dataLen == 0)
                      return 0;
                  byte[] data = new byte[dataLen];
                  dataLen = this.Read(data, dataLen);
                  return buffer.Write(data, dataLen);
              }
       
              //索引器實現
              public byte this[int index]
              {
                  get
                  {
                      if (index >= DataLength())
                          return 0;
                      int rp = readPtr + index;    
                      if (rp >= capacity)
                          rp = rp-(int)capacity;                
                      return pBuf[rp];
                  }
              }
       
              //忽略len長度的數據
              public void Skip(int len)
              {
                  while (len-- > 0) {
                      if (readPtr == writePtr)
                          break;
                      readPtr++;
                      if (readPtr >= capacity)
                          readPtr = 0;
                  }
              }
       
              //判斷是否有數據
              public bool IsEmpty()
              {
                  return writePtr == readPtr;
              }
       
              //獲取有效數據長度
              public int DataLength()
              {
                  int len = writePtr-readPtr;
                  if (len < 0)
                      len = len + (int)capacity;
                  return len;
              }
       
              //清空緩沖區
              public void Clear()
              {
                  writePtr = readPtr = 0;
              }
       
              //緩沖區整理,將數據移動到0位置,方便后續數據的處理
              public void Neaten()
              {
                  uint i, j;
       
                  if (readPtr == 0)
                  {
                      return; //讀指針已經為0
                  }
       
       
                  if (readPtr >= writePtr)
                  {
                      readPtr = writePtr = 0;
                      return;
                  }
       
       
                  if (writePtr >= capacity)
                  {
                      readPtr = 0;
                      writePtr = 0;
                      return;
                  }
       
                  i = 0;
                  j = (uint)readPtr;
                  while (j < writePtr)
                  {
                      pBuf[i++] = pBuf[j++];
                  }
       
                  readPtr = 0;
                  writePtr = (int)i;
              }
              //顯示緩存數據
              public override string ToString()
              {
                  int dataLen = this.DataLength();
                  string str = string.Format("數據長度{0}: ", this.DataLength());
                  for (int i = 0; i < dataLen; i++)
                  {
                      str += string.Format("{0:X} ",this[i]);
                  }
                  return str;
              }
          }
      }
      ————————————————
      ps:通訊接口ICommunication用于將各種通訊方式(網絡,232串口,485總線等)的接口統一,如此上層應用調用統一接口即可,無需關心實際的通訊介質。對于單獨的TCP客戶端而言,此處可以跳過,并無實際意義,不喜歡的小伙伴可自行去掉。
      (責任編輯:admin)本文地址:http://m.bmm520.net/info/net/2021/0711/22472.html

      推薦資訊

      亚洲av无码一区二区三区不卡 | 亚洲Av无码国产一区二区| 亚洲综合亚洲国产尤物| 久久亚洲精品国产精品黑人| 亚洲国产另类久久久精品小说 | 亚洲人成毛片线播放| 久久99亚洲网美利坚合众国| 久久久久亚洲AV成人无码网站| 亚洲AV无码一区二区乱子伦| 亚洲国产精品久久久天堂| 亚洲VA中文字幕不卡无码| 亚洲av无码一区二区乱子伦as| 亚洲av日韩av高潮潮喷无码| 亚洲韩国—中文字幕| 久久久久亚洲av无码专区导航| 亚洲系列国产精品制服丝袜第| 亚洲国产日韩女人aaaaaa毛片在线| 亚洲福利电影一区二区?| 亚洲宅男天堂a在线| 亚洲AV成人无码天堂| 亚洲日韩AV一区二区三区四区 | 国产精品亚洲一区二区三区在线 | 亚洲欧美日韩综合俺去了| 亚洲1区2区3区精华液| 亚洲成A∨人片天堂网无码| 亚洲免费在线观看| 亚洲色成人中文字幕网站| 亚洲AV无码第一区二区三区| 久久亚洲AV成人无码国产| 亚洲人成日本在线观看| 亚洲日本成本人观看| 亚洲 综合 国产 欧洲 丝袜| 伊人久久亚洲综合| 亚洲国产成人久久综合一 | 亚洲日韩在线第一页| 国产亚洲成av人片在线观看 | 久久精品国产亚洲av麻| 亚洲精品在线免费观看| 亚洲一区二区三区高清在线观看 | 亚洲AⅤ优女AV综合久久久| 亚洲无码在线播放|