展示影片

image

先加入 manuStrip

image

using System.Net;           // 網路通訊協定
using System.Net.Sockets;   // 網路插座功能
using System.Threading;     // 多執行緒

1. 設計一個Thread class

public class UDPThread
    {
        ManualResetEvent m_shutdownEvent = new ManualResetEvent(false);
        ManualResetEvent m_pauseEvent = new ManualResetEvent(true);
        Thread m_thread;
        int m_cnt = 0;
        public UDPThread() { }
        public void Job()
        {
            while(true)
            {
                m_pauseEvent.WaitOne(Timeout.Infinite);
                if (m_shutdownEvent.WaitOne(0))
                    break;
                m_cnt++;
            }
        }
        public void Start()
        {
            m_thread = new Thread(Job);
            m_thread.Start();
        }
        public void Pause()
        {
            m_pauseEvent.Reset();
        }
        public void Resume()
        {
            m_pauseEvent.Set();
        }
        public void Stop()
        {
            m_shutdownEvent.Set();
            m_pauseEvent.Set();
            m_thread.Join();
        }
    }


2. 執行緒中如何更新UI?

2.1 加入Label設定/取值功能

public Label CntLabel
{
    set;
    get;
}

2.2 加入更新UpdateUI

public void UpdateUI()
       {
           if (CntLabel.InvokeRequired)
           {
               CntLabel.BeginInvoke( (Action)( () => { UpdateUI(); }) );
           }
           else
           {
               CntLabel.Text = m_cnt.ToString();
           }
       }

2.3 UI加入對應事件

private void 開始ToolStripMenuItem_Click(object sender, EventArgs e)
       {
           udp1= new UDPThread();
           udp1.CntLabel = label1;
           udp1.Start();
           
       }
 
       private void 暫停ToolStripMenuItem_Click(object sender, EventArgs e)
       {
           udp1.Pause();
       }
 
       private void 繼續ToolStripMenuItem_Click(object sender, EventArgs e)
       {
           udp1.Resume();
       }
 
       private void 停止ToolStripMenuItem_Click(object sender, EventArgs e)
       {
           udp1.Stop();
       }
 
       private void 開始ToolStripMenuItem1_Click(object sender, EventArgs e)
       {
           udp2 = new UDPThread();
           udp2.CntLabel = label2;
           udp2.Start();
       }
 
       private void 暫停ToolStripMenuItem1_Click(object sender, EventArgs e)
       {
           udp2.Pause();
       }
 
       private void 繼續ToolStripMenuItem1_Click(object sender, EventArgs e)
       {
           udp2.Resume();
       }
 
       private void 停止ToolStripMenuItem1_Click(object sender, EventArgs e)
       {
           udp2.Stop();
       }

啟動執行緒1和執行緒2後, 畫面如下:

image

2.4 在Form Closing加入防呆

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    if (udp1 != null) udp1.Stop();
    if (udp2 != null) udp2.Stop();
}


=================================================================

3. UI加入IP和PORT設定,

image

3.1 新增IP和Port的存取

image

修改開始執行緒1

image

同時, 修改開始執行緒2

private void 開始ToolStripMenuItem1_Click(object sender, EventArgs e)
{
    udp2 = new UDPThread();
    udp2.IP = textBox1.Text;
    udp2.Port = Convert.ToInt16(numericUpDown2.Value);
    udp2.CntLabel = label2;
    udp2.Start();
}

準備加入監聽InitUDP()和接收資料RecvData()功能

image

3.2 UDP初始化

private void InitUDP()
{
    if (m_udp == null)
        if (JobType == JOBTYPE.RECVDTA)
            m_udp = new UdpClient(Port);                         // 創建一個UDP實體
        else
            m_udp = new UdpClient();
    if (m_IPEP == null) m_IPEP = new IPEndPoint(IPAddress.Parse(IP), Port); // 創建一個連線插座
}

3.3 接收資料RecvData()

public void RecvData()
{
    try
    {
        if (m_udp.Available > 0)           // 很重要, 否則會被咬住
        {
            if(CntLabel.InvokeRequired)
            {
                CntLabel.BeginInvoke( (Action)(() => { RecvData(); }) );
            }else{
                byte[] B = m_udp.Receive(ref m_IPEP);
                CntLabel.Text = Encoding.Default.GetString(B);
            }
        }                
    }
    catch (Exception e)
    {
        //MessageBox.Show(e.Message);
    }
 
    
}

3.4 傳送資料SendData()

public void SendData()
        {
            try
            {
                if (CntLabel.InvokeRequired)
                {
                    CntLabel.BeginInvoke((Action)(() => { SendData(); }));
                }
                else
                {
                    string str = m_cnt.ToString();
                    byte[] B = Encoding.Default.GetBytes(str);
                    m_udp.Send(B, B.Length, IP, Port);
                    CntLabel.Text = str; 
                }
            }
            catch (Exception e)
            {
                //MessageBox.Show(e.Message);
            }
        }

3.5 判定該執行緒執行SendData()或是RecvData()

public  enum JOBTYPE { SENDDATA, RECVDTA };          // 傳送, 接收

3.6 修改Job內容

public void Job()
{
    InitUDP();
    while(true)
    {
        m_pauseEvent.WaitOne(Timeout.Infinite);
        if (m_shutdownEvent.WaitOne(0))
            break;
        m_cnt++;
        
        if (JobType == JOBTYPE.RECVDTA)
        {
            RecvData();
            //UpdateUI();
        }
        else
        {
            SendData();
        }
        Thread.Sleep(m_timeSleep);
    }
}

3.7 修改開始執行緒1

private void 開始ToolStripMenuItem_Click(object sender, EventArgs e)
{
    
    udp1= new UDPThread();
    udp1.IP = textBox1.Text;
    udp1.Port = Convert.ToInt16(numericUpDown1.Value);
    udp1.CntLabel = label1;
    udp1.JobType = JOBTYPE.RECVDTA;
    udp1.Start();
    
}

3.7 修改開始執行緒2

private void 開始ToolStripMenuItem1_Click(object sender, EventArgs e)
{
    udp2 = new UDPThread();
    udp2.IP = textBox1.Text;
    udp2.Port = Convert.ToInt16(numericUpDown1.Value);
    udp2.CntLabel = label2;
    udp2.JobType = JOBTYPE.SENDDATA;
    udp2.Start();
}

=================================================================

3.8 測試結果:

執行緒1: 負責接收

執行緒2: 負責傳送

執行緒1如果臨時暫停, 執行緒2送來的資料還是會保留在bufffer區,

等執行緒1繼續執行, 資料會陸續取出

image


=================================================================

參考資料

1. C# 如何創建, 暫停, 繼續, 終止一個執行緒(Thread)

2. Visual C# 2012 網路程式設計 線上遊戲實作

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 me1237guy 的頭像
    me1237guy

    天天向上

    me1237guy 發表在 痞客邦 留言(0) 人氣()