GComm_TcpServer.cs 7.25 KB
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_TcpServer : IGeneralComm,IDisposable
    {
        /// <summary>
        /// IP 地址 and 端口号
        /// </summary>
        public string Addr { get; set; }

        IPEndPoint LocalEp => 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;
        CancellationTokenSource cts_waitForSend;
        CancellationTokenSource cts_sendTask;

        public GComm_TcpServer(Socket sock)
        {
            this.sock = sock;
            IsConnected = true;
        }
        /// <summary>
        /// 开始
        /// </summary>
        public void Start()
        { 
            if (IsRunning)
                return;
            
            IsRunning = true;
            cts_readTask = new CancellationTokenSource();

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

        /// <summary>
        /// 接收
        /// </summary>
        public void Stop()
        {
            if (!IsRunning)
                return;
            IsRunning = false;
            IsConnected = false;
            cts_readTask.Cancel();
            if (sock != null && sock.Connected)
            {
                sock.Close();
                sock = null;
            }
        }

        void OnTask()
        {
            sendBuf.Clear();
            //启动发送task
            cts_sendTask = new CancellationTokenSource();
            var sendtask = Task.Factory.StartNew(SendTask, cts_sendTask.Token);

            //进入接收task
            ReceiveTask();

            //退出了,肯定连接断开了
            //需要等待 SendTask 也退出了
            cts_sendTask.Cancel();
            sendtask.Wait();

            if (sock != null)
            {
                sock.Close();
                sock = null;
            }

            IsConnected = false;
            IsRunning = false;
        }



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

                DataReceived?.Invoke(this, buf.Take(len).ToArray());
            }

            IsConnected = false;
        }

        /// <summary>
        /// 发送任务
        /// </summary>
        void SendTask()
        {
            while (!cts_sendTask.IsCancellationRequested)
            {
                CancellationTokenSource cts3;

                while (true)
                {
                    byte[] buffer;
                    lock (sendBuf)
                    {
                        if (sendBuf.Count <= 0)
                            break;
                        buffer = sendBuf.ToArray();
                    }

                    int slen;
                    try
                    {
                        slen = sock.Send(buffer);
                    }
                    catch (Exception e)
                    {
                        //连接断开了
                        IsConnected = false;
                        break;
                    }

                    if (slen <= 0)
                    {
                        //连接断开了
                        IsConnected = false;
                        break;
                    }
                    else
                    {
                        lock (sendBuf)
                        {
                            sendBuf.RemoveRange(0, slen);
                        }
                    }
                }

                //重新等 下次被呼醒
                lock (sendBuf)
                {
                    // 呼醒 发送task
                    if (cts_waitForSend == null)
                    {
                        cts_waitForSend = new CancellationTokenSource();
                    }
                    //cts_waitForSend 与 cts_sendTask 合体, 任意一个都会呼醒 delay
                    cts3 = CancellationTokenSource.CreateLinkedTokenSource(cts_waitForSend.Token, cts_sendTask.Token);
                }
                try
                {
                    Task.Delay(-1, cts3.Token).Wait();
                }
                catch (Exception e)
                {
                    //被打断, 有数据需要发送
                }
                lock (sendBuf)
                {
                    cts_waitForSend = null;
                }
            }
        }
        /// <summary>
        /// 无限大,发送缓存
        /// </summary>
        List<byte> sendBuf = new List<byte>();

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="buf"></param>
        public void Write(IEnumerable<byte> buf)
        {
            if (!IsConnected)
                return;

            lock (sendBuf)
            {
                //放入,发送缓存区
                sendBuf.AddRange(buf);

                //呼醒 发送task
                if (cts_waitForSend == null)
                {
                    cts_waitForSend = new CancellationTokenSource();
                }
                cts_waitForSend.Cancel();
                
            }
        }

        /// <summary>
        /// 清空输入缓存
        /// </summary>
        public void DiscardInBuffer()
        {
            //TODO
        }

        public void Dispose()
        {
            Stop();
        }
    }
}