失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > C#实现TCP客户端 可检测断线并自动重连保持连接 对于网线断开或拔掉的情况也可检测到

C#实现TCP客户端 可检测断线并自动重连保持连接 对于网线断开或拔掉的情况也可检测到

时间:2019-09-22 06:35:36

相关推荐

C#实现TCP客户端 可检测断线并自动重连保持连接 对于网线断开或拔掉的情况也可检测到

使用C#实现的TCP客户端,可检测断线(包括网线断开或拔掉),支持断线重连。客户端内部有循环缓冲区异步接收数据,对客户端的读操作会立即返回,根据方法返回值来判断读取数据的字节数。

ps:通讯接口ICommunication用于将各种通讯方式(网络,232串口,485总线等)的接口统一,如此上层应用调用统一接口即可,无需关心实际的通讯介质。对于单独的TCP客户端而言,此处可以跳过,并无实际意义,不喜欢的小伙伴可自行去掉。

对外提供3个事件分别是:

收到数据事件(网络收到数据触发此事件)通讯空闲事件(长时间无数据收发,时间可设)重连失败事件(默认最大支持3次重连,若3次重连仍然失败则触发事件)

使用方式:

//将ReadFromSocket作为线程运行private Thread _socketThread;private TcpClient _client;_socketThread = new Thread(_client.ReadFormSocket);_socketThread.IsBackground = false;_socketThread.Start();//接收数据操作,除此之外还可以注册接收事件,有数据来时读取byte [] recv = new byte[100];mReceive(recv,100);//发送数据byte [] send = new byte[10];for (int i = 0; i < 10; i++)send[i] = i;mSend(send,10);

代码实现:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using .Sockets;using ;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返回0if (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;}}}

如果觉得《C#实现TCP客户端 可检测断线并自动重连保持连接 对于网线断开或拔掉的情况也可检测到》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。