using NLog; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace GeneralGommunication { public class GComm_TcpClient : IGeneralComm { public Logger logger;// = NLog.LogManager.GetCurrentClassLogger(); /// <summary> /// IP 地址 and 端口号 /// </summary> public string Addr { get; set; } IPEndPoint RemoteEp => Misc.StringConverter.ToIPEndPoint(Addr); /// <summary> /// 是否异常 /// </summary> public bool IsError => !string.IsNullOrEmpty(ErrMsg); /// <summary> /// 异常信息 /// </summary> public string ErrMsg { get; private set; } /// <summary> /// 运行中 /// </summary> public bool IsRunning { get; private set; } /// <summary> /// 连接成功 /// </summary> public bool IsConnected { get; private set; } /// <summary> /// 接收task调用 /// </summary> public event IGeneralCommDataReceivedHandler DataReceived; public event PropertyChangedEventHandler PropertyChanged; Socket sock; CancellationTokenSource cts_readTask; /// <summary> /// sock 的线程锁 /// </summary> object sock_lock = new object(); Task task = null; public GComm_TcpClient() { } /// <summary> /// 开始 /// </summary> public void Start() { if (IsRunning) return; IsRunning = true; if (task == null || task.IsCompleted) { //线程已经完成, 创建个新的 cts_readTask = new CancellationTokenSource(); task = Task.Factory.StartNew(OnTask, cts_readTask.Token); } else { //线程还没结束,等待结束后,再创建新的 task.Wait(); cts_readTask = new CancellationTokenSource(); task = Task.Factory.StartNew(OnTask, cts_readTask.Token); } } /// <summary> /// 接收 /// </summary> public void Stop() { if (!IsRunning) return; IsRunning = false; IsConnected = false; cts_readTask.Cancel(); closeSock(); } /// <summary> /// 关闭sock,打断接收,发送中的等待,非OnTask调用 /// </summary> void closeSock() { lock (sock_lock) { if (sock != null && sock.Connected) { sock.Close(); } } } /// <summary> /// 释放sock, 只能在OnTask中调用 /// </summary> void disposeSock() { lock (sock_lock)//lock住,防止外部线程在 sock==null 时,调用sock.Close() { if (sock != null) { sock.Close(); sock = null; } } } void OnTask() { while (!cts_readTask.IsCancellationRequested) { ConnectTask(); if (IsConnected) { //进入接收task ReceiveTask(); //退出了,肯定连接断开了 disposeSock(); } //休息一会儿,再重连 try { Task.Delay(2000, cts_readTask.Token).Wait(); } catch (Exception e) { //被打断了 break; } } disposeSock(); IsConnected = false; } /// <summary> /// 连接任务 /// </summary> void ConnectTask() { while (!cts_readTask.IsCancellationRequested) { try { //sock 的 创建,销毁,只能在 这个线程操作 sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sock.Blocking = true; //1秒内,需要收到信息 sock.ReceiveTimeout = 1000; //1秒内,必须发送完 sock.SendTimeout = 1000; //sock.Connect(RemoteEp); //Connect(sock, RemoteEp, 2000); var result = sock.BeginConnect(RemoteEp, null, null); var sucess = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2)); if (sucess) { sock.EndConnect(result); ErrMsg = null; IsConnected = true; return; } else { disposeSock(); ErrMsg = "连接超时"; } } catch (Exception e) { disposeSock(); //连接出错 //等待重试 ErrMsg = e.Message; } try { Task.Delay(2000, cts_readTask.Token).Wait(); } catch (Exception e) { //被打断 return; } } } /// <summary> /// 接收任务 /// </summary> void ReceiveTask() { byte[] buf = new byte[sock.ReceiveBufferSize]; while (!cts_readTask.IsCancellationRequested) { int len; try { len = sock.Receive(buf); if (len == 0) { continue;//没收到数据,继续等 } } catch (SocketException e) { if (e.SocketErrorCode == SocketError.TimedOut) continue;//超时而已 else if ((e.SocketErrorCode == SocketError.ConnectionAborted) || (e.SocketErrorCode == SocketError.ConnectionRefused) || (e.SocketErrorCode == SocketError.ConnectionReset)) { IsConnected = false; ErrMsg = e.Message; return; } //Console.WriteLine($"ReceiveTask() {e}"); //肯定断开连接了 ErrMsg = e.Message; IsConnected = false; return; } logger?.Debug($"tcp R len={len}"); DataReceived?.Invoke(this, buf.Take(len).ToArray()); } IsConnected = false; } /// <summary> /// 发送数据 /// </summary> /// <param name="buf"></param> public void Write(IEnumerable<byte> buf) { if (!IsConnected) return; int slen; try { slen = sock.Send(buf.ToArray()); logger?.Debug($"tcp W len={slen}"); } catch (Exception e) { //连接断开了 ErrMsg = e.Message; IsConnected = false; return; } if (slen <= 0) { //连接断开了 ErrMsg = "发送数量小于0"; IsConnected = false; return; } } /// <summary> /// 清空输入缓存 /// </summary> public void DiscardInBuffer() { //TODO } } }