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());
}
}
}
调用方法:文章来源:https://www.toymoban.com/news/detail-651373.html
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模板网!