FlyAd2021Comm_TcpClient.cs 7.26 KB
using FlyAd2021.Inc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FlyAd2021
{
    /// <summary>
    /// AD盒2021版,通讯模块,只负责 调用 核心模块 的Rec, Send
    /// </summary>
    public class FlyAd2021Comm_TcpClient : IFlyAd2021Comm
    {
        /// <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 Action<byte[]> RecMsg;



        public event PropertyChangedEventHandler PropertyChanged;

        Socket sock;
        CancellationTokenSource cancellation;
        CancellationTokenSource cancellation_waitforSend;


        public FlyAd2021Comm_TcpClient()
        {

        }
        /// <summary>
        /// 开始
        /// </summary>
        public void Start()
        {
            if (IsRunning)
                return;
            IsRunning = true;
            cancellation = new CancellationTokenSource();

            Task.Factory.StartNew(OnTask, cancellation.Token);
        }

        /// <summary>
        /// 接收
        /// </summary>
        public void Stop()
        {
            if (!IsRunning)
                return;
            IsRunning = false;

            cancellation.Cancel();
            if (sock != null && sock.Connected)
            {
                sock.Close();
                sock = null;
            }
        }

        void OnTask()
        {
            while (!cancellation.IsCancellationRequested)
            {
                ConnectTask();

                if (IsConnected)
                {
                    sendBuf.Clear();
                    //启动发送task
                    Task.Factory.StartNew(SendTask, cancellation.Token);

                    //进入接收task
                    ReceiveTask();
                    //退出了,肯定连接断开了
                }

                //休息一会儿,在重连
                try
                {
                    Task.Delay(2000, cancellation.Token).Wait();
                }
                catch (Exception e)
                {
                    //被打断了
                    break;
                }
            }

            IsConnected = false;
        }

        /// <summary>
        /// 连接任务
        /// </summary>
        void ConnectTask()
        {
            sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            sock.Blocking = true;



            //1秒内,需要收到信息
            sock.ReceiveTimeout = 1000;
            //1秒内,必须发送完
            sock.SendTimeout = 1000;

            while (!cancellation.IsCancellationRequested)
            {
                try
                {
                    sock.Connect(RemoteEp);
                    IsConnected = true;
                    ErrMsg = null;
                    return;
                }
                catch (SocketException e)
                {
                    //连接出错
                    //等待重试
                    ErrMsg = e.Message;
                }
                try
                {
                    Task.Delay(2000, cancellation.Token).Wait();
                }
                catch (Exception e)
                {
                    //被打断
                    return;
                }
            }
        }

        /// <summary>
        /// 接收任务
        /// </summary>
        void ReceiveTask()
        {
            byte[] buf = new byte[0x10000];
            while (!cancellation.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;
                        return;
                    }
                    //Console.WriteLine($"ReceiveTask() {e}");
                    //肯定断开连接了
                    IsConnected = false;
                    break;
                }

                RecMsg?.Invoke(buf.Take(len).ToArray());
            }
            if (sock != null)
            {
                sock.Close();
            }
            IsConnected = false;
        }

        /// <summary>
        /// 发送任务
        /// </summary>
        void SendTask()
        {
            while (!cancellation.IsCancellationRequested)
            {
                while (sendBuf.Count > 0)
                {
                    int slen;
                    try
                    {
                        slen = sock.Send(sendBuf.ToArray());
                    }
                    catch (Exception e)
                    {
                        //连接断开了
                        IsConnected = false;
                        break;
                    }
                    if (slen > 0)
                        sendBuf.RemoveRange(0, slen);
                    else if (slen <= 0)
                    {
                        //连接断开了
                        IsConnected = false;
                        break;
                    }
                }

                //重新等 下次被呼醒
                cancellation_waitforSend = new CancellationTokenSource();
                try
                {
                    Task.Delay(-1, cancellation_waitforSend.Token).Wait();
                }
                catch (Exception e)
                {
                    //被打断, 有数据需要发送
                }
            }
        }
        /// <summary>
        /// 无限大,发送缓存
        /// </summary>
        List<byte> sendBuf = new List<byte>();

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="msg"></param>
        public void SendMsg(byte[] msg)
        {
            if (!IsConnected)
                return;



            //放入,发送缓存区
            sendBuf.AddRange(msg);

            //呼醒 发送task
            cancellation_waitforSend.Cancel();
        }
    }

}