C# TcpClient 断线重连升级版--终结版

这篇具有很好参考价值的文章主要介绍了C# TcpClient 断线重连升级版--终结版。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Drawing;

namespace TorqueCollecct
{
    class AsyncTcpClient
    {
        private string ip;
        private string detailfilename;
        private int port;
        public byte Delimiter = 0x00; // NUL    接受信息的分隔符
        private bool IsClose = false;
        //单例
        private TcpClient tcpClient;
        //连接服务器
        public void ConnectServer(string _ip, int _port)
        {
            ip = _ip;
            port = _port;
            detailfilename = ip.Replace(".", "_");
            try
            {
                if (tcpClient != null)
                {
                    tcpClient.Close();
                }
                tcpClient = new TcpClient();
                Task.Factory.StartNew(() => ReCon(), TaskCreationOptions.LongRunning);
                Task.Factory.StartNew(() => PingOC(), TaskCreationOptions.LongRunning);
                Task.Factory.StartNew(() => ReceivedData(), TaskCreationOptions.LongRunning);
            }
            catch (Exception e)
            {
            }
        }
        private void ReCon()
        {
            while (!IsClose)
            {
                try
                {
                    if (tcpClient.Client != null && tcpClient.Connected)
                    {
                        SetCon(1);
                    }
                    else
                    {
                        //SetCon(-1);
                        SetCon(0);
                        //断线重连
                        tcpClient.Close();
                        tcpClient = new TcpClient();
                        //异步连接,有连接超时时间
                        tcpClient.ConnectAsync(ip, port).Wait(2000);
                        //tcpClient.Connect(ip, port);
                    }
                }
                catch (Exception ex)
                {
                    Form1.mt.Show(ex.Message, true, detailfilename);
                }
                Thread.Sleep(1000);
            }
        }
        private List<byte> _queuedMsg = new List<byte>();

        private void ReceivedData()
        {
            while (!IsClose)
            {
                try
                {
                    if (tcpClient == null || tcpClient.Client == null || tcpClient.Connected == false || tcpClient.Available == 0)
                    {
                        Thread.Sleep(100);
                        continue;
                    }
                    List<byte> bytesReceived = new List<byte>();
                    while (tcpClient.Available > 0 && tcpClient.Connected)
                    {
                        byte[] nextByte = new byte[1024];
                        //读取的实际长度
                        // 尝试过数组的Copy 与 元素查找 但效率不及下方写法
                        int recCount = tcpClient.Client.Receive(nextByte, 0, 1024, SocketFlags.None);
                        for (int i = 0; i < recCount; i++)
                        {
                            if (nextByte[i] == Delimiter)
                            {
                                byte[] msg = _queuedMsg.ToArray();
                                string Rcmsg = Encoding.ASCII.GetString(msg.ToArray());
                                _queuedMsg.Clear();
                               
                                MyEventArgs e = new MyEventArgs(ip, Rcmsg);
                                _MsgChange(e);
                            }
                            else
                            {
                                _queuedMsg.Add(nextByte[i]);
                            }
                        }
                    }
                    //急速采集则屏蔽下面的休眠
                    Thread.Sleep(10);
                }
                catch (Exception)
                {

                }
                //急速采集则屏蔽下面的休眠
                Thread.Sleep(1000);
            }
        }


        //发送消息
        public bool SendMsg(string msg)
        {
            //发送XXXX0001_000000000000_   (没有下划线)             
            //接收00570002_000000000000_010001020103
            try
            {
                //数据部分
                byte[] bt_Data = Encoding.ASCII.GetBytes(msg);
                byte[] bt_head = Encoding.ASCII.GetBytes((bt_Data.Length + 4).ToString("0000"));
                byte[] bt_send = new byte[bt_Data.Length + 5];
                for (int i = 0; i < bt_head.Length; i++)
                {
                    bt_send[i] = bt_head[i];
                }
                for (int i = 0; i < bt_Data.Length; i++)
                {
                    bt_send[i + 4] = bt_Data[i];
                }
                bt_send[bt_send.Length - 1] = 0x00;
                //开始异步发送
                try
                {
                    tcpClient.GetStream().BeginWrite(bt_send, 0, bt_send.Length, (ar) =>
                    {
                        tcpClient.GetStream().EndWrite(ar);//结束异步发送
                    }, null);
                }
                catch (Exception ex)
                {
                    string abc = ex.ToString();
                }
                return true;
            }
            catch (Exception ex)
            {
                SetCon(-1);
                SetCon(0);
                return false;
            }
        }
        public bool SendMsg(byte[] msg)
        {
            try
            {
                //开始异步发送
                tcpClient.GetStream().BeginWrite(msg, 0, msg.Length, (ar) =>
                {
                    tcpClient.GetStream().EndWrite(ar);//结束异步发送
                }, null);
                return true;
            }
            catch (Exception ex)
            {
                //尝试重连。。。。。。"
                SetCon(-1);
                SetCon(0);
                return false;
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void Close()
        {
            IsClose = true;
            if (tcpClient != null)
            {
                try
                {
                    tcpClient?.Close();
                }
                catch (Exception)
                {
                }
            }
        }

        public int isConnected = -1;
        /// <summary>
        /// -1 初始化  0 未连接  1 连接
        /// </summary>
        /// <param name="_con"></param>
        private void SetCon(int _con)
        {
            if (isConnected != _con)
            {
                bool rel = false;
                if (_con == 1)
                {
                    rel = true;
                }
                isConnected = _con;
                MyEventArgs e = new MyEventArgs(ip + "__" + port.ToString(), rel);
                _ConChange(e);
            }
        }
        private void PingOC()
        {
            Ping ping = new Ping();
            int failcount = 0;
            while (!IsClose)
            {
                try
                {
                    PingReply pingReply = ping.Send(ip, 1000);
                    //网络状态
                    if (pingReply.Status != IPStatus.Success)
                    {
                        failcount++;
                        Form1.mt.Show("Ping,网络故障,掉线" + failcount.ToString() + "次", true, detailfilename);

                        if (failcount > 2 && isConnected != 0)
                        {
                            //3秒通信失败则网络已断开!
                            tcpClient.Client = null;
                            tcpClient.Close();
                        }
                    }
                    else
                    {
                        failcount = 0;
                    }
                    Thread.Sleep(1000);
                }
                catch (Exception)
                {

                }
            }
        }

        public class MyEventArgs : EventArgs
        {
            public string IP;
            public bool IsConnetct;
            public byte[] Msg;
            public string msg;
            public MyEventArgs(string iP, byte[] msg)
            {
                IP = iP;
                Msg = msg;
            }
            public MyEventArgs(string iP, string _msg)
            {
                IP = iP;
                msg = _msg;
            }
            public MyEventArgs(string iP, bool iscon)
            {
                IP = iP;
                IsConnetct = iscon;
            }
        }
        //连接状态
        public delegate void ConChange(object sender, MyEventArgs args);
        public event ConChange OnConChange;
        protected virtual void _ConChange(MyEventArgs e)
        {
            if (OnConChange != null)
            {
                OnConChange(this, e);
            }
        }
        //收到的消息
        public delegate void MsgChange(object sender, MyEventArgs args);
        public event MsgChange OnMsgChange;
        protected virtual void _MsgChange(MyEventArgs e)
        {
            if (OnMsgChange != null)
            {
                OnMsgChange(this, e);
            }
        }
    }
}

针对 数据报 解析参考:  消息字节总长度+消息内容的解析参考:

 private void OnRecvData()
        {
            byte[] buffer = new byte[4320];//1440*3
            int iHasRead = 0;
            while (IsConnected())
            {
                try
                {
                    int iRet = Receive(buffer, iHasRead, buffer.Length - iHasRead, SocketFlags.None);
                    if (iRet <= 0)
                    {
                        continue;
                    }
                    iHasRead += iRet;
                    if (iHasRead < 1440)
                    {
                        continue;
                    }

                    bool bHasFound = false;//是否找到数据包头了
                    for (int i = 0; i < iHasRead; ++i)
                    {
                        //找到消息头  等同 BitConverter.ToInt16(buffer, 0);
                        int iMsgSize = buffer[i + 1];
                        iMsgSize <<= 8;
                        iMsgSize |= buffer[i];
                        iMsgSize &= 0x00FFFF;
                        if (1440 != iMsgSize)
                        {
                            continue;
                        }
                        //校验
                        ulong checkValue = BitConverter.ToUInt64(buffer, i + 48);
                        if (0x0123456789ABCDEF == checkValue)
                        {//找到了校验值
                            bHasFound = true;
                            if (i != 0)
                            {//说明存在粘包,要把前面的数据清理掉
                                iHasRead = iHasRead - i;
                                Array.Copy(buffer, i, buffer, 0, buffer.Length - i);
                            }
                            break;
                        }
                    }
                    if (!bHasFound)
                    {//如果没找到头,判断数据长度是不是快超过了总长度,超过了,说明数据全都有问题,删掉
                        if (iHasRead >= buffer.Length) iHasRead = 0;
                        continue;
                    }
                    //再次判断字节数是否够
                    if (iHasRead < 1440)
                    {
                        continue;
                    }
                    iHasRead = iHasRead - 1440;
                    //按照协议的格式解析数据 buffer 就是完整的包
                    ParseData(buffer);
                    //按照协议的格式解析数据 buffer 就是完整的包
                    Array.Copy(buffer, 1440, buffer, 0, buffer.Length - 1440);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine("recv thread:" + ex.ToString());
                }
            }
        }

调用方法:

AsyncTcpClient sw = new AsyncTcpClient();
sw.OnConChange += Sw_OnConChange;
sw.OnMsgChange += Sw_OnMsgChange;
sw.ConnectServer(ip, port);


 private void Sw_OnConChange(object sender, AsyncTcpClient.MyEventArgs args)
        {
            if (args.IsConnetct)
            {
                this.Invoke((EventHandler)delegate
                {
                    timer1.Enabled = true;
                    lab_Con.Text = "联机";
                    lab_Con.BackColor = Color.Green;
                    timer1.Enabled = true;
                });
            }
            else
            {
                this.Invoke((EventHandler)delegate
                {
                    timer1.Enabled = false;
                    lab_Con.Text = "断开";
                    lab_Con.BackColor = Color.Red;
                    timer1.Enabled = false;
                });
            }
        }

  private static readonly object LOCK = new object();
        private void Sw_OnMsgChange(object sender, AsyncTcpClient.MyEventArgs args)
        {
            //加把锁,逐条解析
            lock (LOCK)
            {
                //Show("接收:" + args.msg);
            }
        }


        public void Close()
        {
            try
            {
                sw.OnConChange -= Sw_OnConChange;
                sw.OnMsgChange -= Sw_OnMsgChange;
                sw.Close();
            }
            catch (Exception)
            {
            }
        }

增加了消息分割 文章来源地址https://www.toymoban.com/news/detail-651373.html

到了这里,关于C# TcpClient 断线重连升级版--终结版的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WebSocket的心跳机制和断线重连

    在服务器重启或是弱网情况下,前端不能保证一直连接成功。因此在出现被动断开的情况下,需要有 心跳机制 和 断线重连 的功能。 心跳机制 :客户端每隔一段时间向服务端发送一个特有的心跳消息,每次服务端收到消息后只需将消息返回,此时,若二者还保持连接,则客

    2024年01月18日
    浏览(43)
  • Java连接websocket优雅断线、重连功能

          为了实现优雅重连和重试,您需要在代码中添加一些逻辑来处理连接失败或断开连接的情况。 实现代码如下:

    2024年02月10日
    浏览(36)
  • websocket前端封装代码,心跳机制断线重连

    websocket是一种全双工通信长链接,大多用来实现及时通讯,数据实时性要求较为高的地方,在websoket未出现的时候前端使用的setInterval轮训进行数据更新的,在那些对于数据实时性要求不高地方我们仍可以使用 轮训。 (1)建立在 TCP 协议之上,服务器端的实现比较容易。 (

    2024年02月11日
    浏览(52)
  • websocket的基础使用,心跳机制,断线重连

    websoket出现的原因: 传统的http请求只能是由前端向后台发送一个请求,然后后台把结果返回给前端,前端再进行展示。这里就暴露了一个问题,就是通信只能由前端发起,而后台无法主动与前端通信。而websoket的出现就是为了解决这个问题,让前端可以主动联系后台,后台也

    2024年02月06日
    浏览(48)
  • uniapp使用WebSocket断线,心跳重连机制

    提示:我们在使用WebSocket,经常会遇到有的时候给别人发消息,别人会接收不到,这个时候就有可能是WebSocket断线了,所以这个时候心跳包就出现了 提示:可直接使用,记得把对应地址替换一下

    2024年04月12日
    浏览(42)
  • java实现WebSocket客户端&&断线重连机制

    1、引入maven依赖(注意版本) 2、代码

    2024年02月16日
    浏览(46)
  • C++ TCP/IP 关于tcp断线重连的问题

    在工控上经常用到tcp连接,比如串口服务器或某些支持modbustcp协议的仪表等,以前尽量使用串口服务器的虚拟串口功能,现在逐步使用上了tcpserver或tcpclient模式。 搜索了个C++ 的tcp断线重连的案例(http://www.cnblogs.com/kingdom_0/articles/2571727.html),使用这个的原因还因其使用的是

    2024年02月10日
    浏览(30)
  • ai问答:vue3+pinia+WebSocket 封装断线重连(实战)

    把 Socket 实例 挂载到全局 为方便梳理,请忽略 typescript ,一切尽在注释中 Socket封装(断线重连) 这个 WebSocket 类封装了 WebSocket 的连接、重连、发送数据等方法。 在 connect 方法中,它会连接 WebSocket ,并绑定相关事件监听。 在 onclose 事件中,它会调用 reconnect 方法进行重连。 recon

    2024年02月03日
    浏览(53)
  • Android中okhttp的websocket的详细使用方法(加断线重连)

    介绍之类的就不多讲了,懒得讲也未必有别人整理的清晰,直接上代码 使用:

    2024年02月15日
    浏览(33)
  • C++ Qt TCP的心跳检测机制,断线重连技术,应用层代码重新实现

    目录 前言: 一、Qt直接启动本身的KeepAlive 二、在应用层自己实现一个心跳检测  三、自定义心跳代码实现: 完整客户端服务端工程下载: 共用的结构体相关头文件:         客户端部分核心代码:         服务端部分核心代码: 运行结果展示: 前两篇关于qt tcp 相关的,

    2024年02月05日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包