C# 异步倒计时

C# 异步倒计时

使用C#测试tcp端口连接,我们肯定会想到TcpClient,然后使用tcpclient.Connect()方法,这种方法是可行的,但是有缺陷,是什么呢?使用tcpclient.Connect()方法,程序会等待该方法执行结束后才会继续执行下面的程序段,并且没有超时时间可设置,这样会大大影响程序执行的效率和时间。

如果我们使用tcpclient.BeginConnect()方法,执行效率就会提升很多,并且还可以设置程序超时时间,具体代码如下:

TcpClient tcp = new TcpClient();

var result = tcp.BeginConnect(IP或域名, 端口, null, null);

var sucess = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2));

if (!sucess)

{

}

else

{

}

tcp.EndConnect(result);

具体代码就是这样了,实现过程就是获取用于等待异步操作完成的WaitHandle,阻止当前线程,直到当前实例收到信号,同时使用TimeSpan指定时间间隔。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UIFrame;
using DemoProject;
using UnityEngine.UI;
using System;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.IO;
using System.Text;
using Unity.UIWidgets.material;

public class CountDownTimer : MonoBehaviour
{
    // 剩余总时间
    private int totaltime1 = 5;
    private int totaltime2 = 6;
    private int totaltime3;
    private int totaltime4;

    private float intervaletime=1;

    // UI倒计时显示文本
    public Text countdown1text;
    public Text countdown2text;
    public Text countdown3text;
    public Text countdown4text;
    private DateTime dt;

    void Start()
    {
        // UI倒计时显示的格式
        countdown1text.text = string.Format("{0:00}:{1:00}", (int)totaltime1 / 60, (float)totaltime1 % 60);
        countdown2text.text = string.Format("{0:00}:{1:00}", (int)totaltime2 / 60, (float)totaltime2 % 60);
        countdown3text.text = string.Format("{0:00}:{1:00}:{2:00}", 24-(int)totaltime3, 60-((int)totaltime3 / 60), 60-((float)totaltime3 % 60));
        countdown4text.text = string.Format("{0:00}:{1:00}:{2:00}", (int)totaltime4/60/60, ((int)totaltime4/60%60), ((int)totaltime4%60));

        Debug.Log("开始倒计时迭代器协程");
        StartCoroutine(CountDown());
        StartCoroutine( LocalTimeControlIE());
        StartCoroutine( NetworkTimeControlIE());
    }

    // 实现倒计时方法一:用IEnumerator协程迭代器
    IEnumerator CountDown()
    {


        while (totaltime1 >=0)
        {
            int M = (int)(totaltime1 / 60);
            float S = totaltime1 % 60;

            // 显示格式为 M分:S秒
            countdown1text.GetComponent<Text>().text = string.Format("{0:00}:{1:00}", M,S);
            // 每一帧update后等待1秒延迟再继续下一帧
            yield return new WaitForSeconds(1);
            // 时间减去一秒
            totaltime1--;

            // 计时器复位重新开始计时

            if (totaltime1 < 0)
            {
                totaltime1 = 20;
            }
        }
    }


    // 实现倒计时方法二:采用Update方法
    // Update is called once per frame
    void Update()
    {
        Debug.Log("开始Update倒计时");
        
            int M = (int)(totaltime2 / 60);
            float S = totaltime2 % 60;
            if (totaltime2 > 0)
            {
                intervaletime -= Time.deltaTime;
                if (intervaletime <= 0)
                {
                    intervaletime += 1;
                    totaltime2--;
                    countdown2text.text = string.Format("{0:00}:{1:00}", M, S);

                }
            }
            if (totaltime2 <= 0)
            {
                totaltime2 = 20;
            }
        
    }


    // 获取本地操作系统的时间来倒计时
    /// <summary>
    /// 计时携程
    /// </summary>
    /// <returns></returns>
    IEnumerator LocalTimeControlIE()
    {
        while (true)
        {
            int H = (int)(23 - System.DateTime.Now.Hour);
            int M = (int)(60 - System.DateTime.Now.Minute);
            int S = (int)(60 - System.DateTime.Now.Second);
            countdown3text.text = "本地时间倒计时\n"  + string.Format("{0:00}:{1:00}:{2:00}", H, M, S);
            yield return new WaitForSeconds(1.0f);
        }
    }



// Constructor
//public void myMainPage()
//{
//        //判断当前网络连接状态

//        Network nw = new Network();

//        if (nw.IsAvailable)

//            lbmsg.Text = "网络已连接";

//        else

//            lbmsg.Text = "网络已断开";
//        //InitializeComponent();

//        // Subscribe to the NetworkAvailabilityChanged event
//        DeviceNetworkInformation.NetworkAvailabilityChanged += new EventHandler<NetworkNotificationEventArgs>(NetworkAvailabilityChanged);
//}

//void NetworkAvailabilityChanged(object sender, NetworkNotificationEventArgs e)
//{

//    string msg = "";
//    if (e.IsAvailable)
//    {
//        msg = "网络已连接";

//    }
//    else
//    {
//        msg = "网络已断开";
//    }
//    Dispatcher.BeginInvoke(() => {
//        lbmsg.Text = msg;
//    });
//}

// 请求网络时间来倒计时
/// <summary>
/// 计时携程
/// </summary>
/// <returns></returns>
IEnumerator NetworkTimeControlIE()
    {
        Debug.Log("开始网络倒计时协程");

        int nH = 00;
        int nM = 00;
        int nS = 00;

        Debug.Log("开始判断网络连接状态。");
        string url = "www.baidu.com;www.sina.com;www.cnblogs.com;www.google.com;www.163.com;www.csdn.com";
        string[] urls = url.Split(new char[] { ';' });
        if (CheckServeStatus(urls) )
        {

            Debug.Log(" 侦测到网络连接正常,开始获取网络时间");
            nH = (int)DataStandardTime().Hour;
            nM = (int)DataStandardTime().Minute;
            nS = (int)DataStandardTime().Second;
            totaltime4 = 86400 - ((nH * 60 * 60) + (nM * 60) + nS);
        }
        else
        {
            Debug.Log(" 侦测到网络连接异常,时间设置为10秒");
            totaltime4 =10;
        }


        while (totaltime4>=1)
        {
            Debug.Log("开始倒计时");
            int H = (int)totaltime4 / 60 / 60;
            int M = (int)totaltime4 / 60 % 60;
            int S = (int)totaltime4 % 60;
            countdown4text.text = "网络时间倒计时\n" + string.Format("{0:00}:{1:00}:{2:00}", H, M, S);
            yield return new WaitForSeconds(1.0f);
            // 时间减去一秒
            totaltime4--;

            // 计时器复位重新开始计时
            if (totaltime4 < 1)
            {
                totaltime4 = 86400-((nH * 60 * 60) + (nM*60) + nS);
            }

        }
    }

    // 判断网络状态

    //public string GetHostNameByIp(string ip)
    //{
    //    ip = ip.Trim();
    //    if (ip == string.Empty)
    //        return string.Empty;
    //    //System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
    //    //{
    //        try
    //        {
    //            // 是否 Ping 的通 
    //            if (System.Net.NetworkInformation.Ping(ip))
    //            {
    //                System.Net.IPHostEntry host = System.Net.Dns.GetHostEntry(ip);
    //                return host.HostName;
    //            }
    //            else
    //                return string.Empty;
    //        }
    //        catch (Exception)
    //        {
    //            return string.Empty;
    //        }
    //    //}
    //}



    /// <summary>
    /// 检测网络连接状态
    /// </summary>
    /// <param name="urls"></param>
    //public static void CheckServeStatus(string[] urls)
    public bool CheckServeStatus(string[] urls)
    {

        int errCount = 0;//ping时连接失败个数

        //if (!LocalConnectionStatus())
        //{
        //    Console.WriteLine("网络异常~无连接");
        //}
        if (!MyPing(urls, out errCount))
        {
            if ((double)errCount / urls.Length >= 0.3)
            {
                Debug.Log("网络连接异常");
                return false;
                //Console.WriteLine("网络异常~连接多次无响应");
            }
            //else
            //{
             //   Console.WriteLine("网络不稳定");
            //}
            else
            {
                Debug.Log("网络连接正常");
                return true;
            }
        }
        else
        {
                Debug.Log("网络连接正常");
            return true;
            //Console.WriteLine("网络正常");
        }
    }

    /// <summary>
    /// Ping命令检测网络是否畅通
    /// </summary>
    /// <param name="urls">URL数据</param>
    /// <param name="errorCount">ping时连接失败个数</param>
    /// <returns></returns>
    public static bool MyPing(string[] urls, out int errorCount)
    {
        bool isconnected = true;
        System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
        errorCount = 0;
        try
        {
            PingReply pr;
            for (int i = 0; i < urls.Length; i++)
            {
                pr = ping.Send(urls[i]);
                if (pr.Status != IPStatus.Success)
                {
                    isconnected = false;
                    errorCount++;
                }
                Console.WriteLine("Ping " + urls[i] + "    " + pr.Status.ToString());
            }
        }
        catch
        {
            isconnected = false;
            errorCount = urls.Length;
        }
        //if (errorCount > 0 && errorCount < 3)
        //  isconn = true;
        return isconnected;
    }

    //public static DateTime DataStandardTime()//使用时,将static 关键字删除,在其它位置方可使用
    public DateTime DataStandardTime()//使用时,将static 关键字删除,在其它位置方可使用
    {//返回国际标准时间
     //只使用的TimerServer的IP地址,未使用域名
        string[,] TimerServer = new string[14, 2];
        int[] ServerTab = new int[] { 3, 2, 4, 8, 9, 6, 11, 5, 10, 0, 1, 7, 12 };

        TimerServer[0, 0] = "time-a.nist.gov";
        TimerServer[0, 1] = "129.6.15.28";
        TimerServer[1, 0] = "time-b.nist.gov";
        TimerServer[1, 1] = "129.6.15.29";
        TimerServer[2, 0] = "time-a.timefreq.bldrdoc.gov";
        TimerServer[2, 1] = "132.163.4.101";
        TimerServer[3, 0] = "time-b.timefreq.bldrdoc.gov";
        TimerServer[3, 1] = "132.163.4.102";
        TimerServer[4, 0] = "time-c.timefreq.bldrdoc.gov";
        TimerServer[4, 1] = "132.163.4.103";
        TimerServer[5, 0] = "utcnist.colorado.edu";
        TimerServer[5, 1] = "128.138.140.44";
        TimerServer[6, 0] = "time.nist.gov";
        TimerServer[6, 1] = "192.43.244.18";
        TimerServer[7, 0] = "time-nw.nist.gov";
        TimerServer[7, 1] = "131.107.1.10";
        TimerServer[8, 0] = "nist1.symmetricom.com";
        TimerServer[8, 1] = "69.25.96.13";
        TimerServer[9, 0] = "nist1-dc.glassey.com";
        TimerServer[9, 1] = "216.200.93.8";
        TimerServer[10, 0] = "nist1-ny.glassey.com";
        TimerServer[10, 1] = "208.184.49.9";
        TimerServer[11, 0] = "nist1-sj.glassey.com";
        TimerServer[11, 1] = "207.126.98.204";
        TimerServer[12, 0] = "nist1.aol-ca.truetime.com";
        TimerServer[12, 1] = "207.200.81.113";
        TimerServer[13, 0] = "nist1.aol-va.truetime.com";
        TimerServer[13, 1] = "64.236.96.53";
        int portNum = 13;
        string hostName;
        byte[] bytes = new byte[1024];
        int bytesRead = 0;

        string strResponse = null;
        string str2 = null;


        System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient();
        for (int i = 0; i < 13; i++)
        {
            hostName = TimerServer[ServerTab[i], 0];

            Debug.Log("开始请求远端服务器 hostName:" + hostName);
            try
            {
                // 同步连接服务器
                // client.Connect(hostName, portNum);

                // 异步连接服务器
                // client.BeginConnect(hostName, Convert.ToInt32(portNum), new AsyncCallback(ConnectCallback),client);
                Debug.Log("开始异步连接服务器");
                var connectResult = client.BeginConnect(hostName, portNum, null, null);
                var connectOK = connectResult.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
                Debug.Log("连接服务器状态:"+connectOK);
                if (!connectOK)
                {
                    Debug.Log("网络未连接");
                    client.Close();
                    break;
                }
                else
                {
                    System.Net.Sockets.NetworkStream ns = client.GetStream();
                    Debug.Log("开始获取网络字节流:"+ns);

                    // 同步读取
                    //if (ns.CanRead)
                    //{
                    //    bytesRead = ns.Read(bytes, 0, bytes.Length);
                    //    client.Close();
                    //    ns.Close();
                    //    break;
                    //}
                    //else
                    //{
                    //    client.Close();
                    //    ns.Close();
                    //    Debug.Log("网络错误!");
                    //    break;
                    //}

                    // 异步读取
                    try
                    {

                        byte[] result = new byte[client.Available];
                        ns.BeginRead(result, 0, result.Length, new AsyncCallback(MyReadCallback), ns);
                        Debug.Log("开始异步接收网络数据:"+ns);
                        strResponse = Encoding.ASCII.GetString(result).Trim();
                        Debug.Log("得到异步接收的网络数据 strResponse ntp time:" +strResponse);
                        str2 = strResponse;

                        client.Close();
                        break;
                    }
                    catch 
                    { 
                        Debug.Log("网络错误!");

                    }

                }

                // client.EndConnect(connectResult);
                MyConnectCallback(connectResult);
            }
            catch (System.Exception)
            {
                Debug.Log("获取错误!");
            }
        }

        Debug.Log("得到 ntp time:" + str2);

        if (str2 != null)
        {
            char[] sp = new char[1];
            sp[0] = ' ';
            System.DateTime dt = new DateTime();
            //string str1;
            //str2 = System.Text.Encoding.ASCII.GetString(bytes, 0, bytesRead);
            str2 = str2.Replace("PDT", "");
    
            string[] s;
            //s = str1.Split(sp);
            s = str2.Split(sp);
            // "58961 20-04-22 07:22:32 50 0 0 900.6 UTC(NIST) *"
            dt = System.DateTime.Parse(s[1] + " " + s[2]);//得到标准时间
            //Debug.WriteLine("get:" + dt.ToShortTimeString());
            Debug.Log("得到标准时间:" + dt.ToShortTimeString());
            //dt=dt.AddHours (8);
            dt = dt.ToLocalTime();
            Debug.Log("得到本地时间:" + dt);
            return dt;
        }
        else
        {
            dt = System.DateTime.Parse("20200000000000");
            Debug.Log(" 获取网络时间失败,已经获取到本机系统时间.");
            return dt;
        }

    }

    private static void MyReadCallback(IAsyncResult iar)
    {
        //
        NetworkStream ns = (NetworkStream)iar.AsyncState;
        byte[] read = new byte[1024];
        String data = "";
        int recv;

        recv = ns.EndRead(iar);
        data = String.Concat(data, Encoding.ASCII.GetString(read, 0, recv));

        //接收到的消息长度可能大于缓冲区总大小,反复循环直到读完为止
        while (ns.DataAvailable)
        {
            ns.BeginRead(read, 0, read.Length, new AsyncCallback(MyReadCallback), ns);
        }
        //打印
        Console.WriteLine("您收到的信息是" + data);
        Debug.Log("您收到的信息是" + data);

    }

    private void MyConnectCallback(IAsyncResult ar)
    {
        TcpClient t = (TcpClient)ar.AsyncState;
        try
        {
            if (t.Connected)
            {
                t.EndConnect(ar);//函数运行到这里就说明连接成功
            }
            else
            {
            }
        }
        catch 
        { }
    }


}