異世界


2017年10月17日 星期二

UDP Server (更新)

/* ==  如何使用 jUdpServer  ================================================================

1. 將該程式 namespace 改成與主程式相同命名空間

2. 於主程式 :
 2.1. 定義一個 UDP Server 欄位:
     jUdpServer jUDP_Server;

 2.2. 建一個事件處理程序,來處理 UdpReceived 事件
     private void DoUdpReceived(object sender, UdpEventArgs e)
     {
            Byte[] bytes = jUdpServer.StreamToBytes(e.MSG);

            //.. Show UDP MSG  ..//
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(BitConverter.ToString(bytes));
            txtUdpView.Text += sb.ToString();

     }
 2.3. 建一個 Function 來啟動與監聽 UDP 如下:
     private void UDP_StartListen(object sender)
     {
         // NPortUDP = new jUdpServer(sender, txtIP.Text, Convert.ToInt16(txtPort.Text));
         jUDP_Server = new jUdpServer(sender, Convert.ToInt16(txtLocalPort.Text));
         jUDP_Server.UdpReceived += DoUdpReceived; //..指定 UdpReceived 事件處理程序
         jUDP_Server.StartListen();
     }

3. 內已包含 UDP-Send 函式,
   函式結構 : UDP_Send(String RemoteIP, int RemotePort, byte[] TxBuffer, int ByteCount);
   用法如下:
     byte[] bytes = new byte[1,2,3,....,9];
     jUDP_Server.UDP_Send("192.168.100.100", 4001, bytes, 5);
======================================================================================*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace MyUdpServer
{
   
    /// <summary>
    /// 事件委派宣告
    /// </summary>
    public delegate void UdpEventHandler(object sender, UdpEventArgs e);
   // public delegate void AlarmSummeryEventHandler(object sender, AlarmSummeryEventArgs e);
   
    public class jUdpServer
    {     
        #region Client端 方法
        Socket m_SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        IPAddress m_RemoteAddress = new IPAddress(0);
        public int UDP_Send(String RemoteIP, int RemotePort, byte[] TxBuffer, int ByteCount)
        {
            //("遠端IP位置 : ");
            // IPAddress m_RemoteAddress = IPAddress.Parse(RemoteIP) ;
            // if (m_RemoteAddress != null)
            if (IPAddress.TryParse(RemoteIP, out m_RemoteAddress))
            {
                /*初始化IPEndPoint物件,表示要連結的遠端IP位置和Port號*/
                EndPoint m_IPPoint = new IPEndPoint(m_RemoteAddress, RemotePort);
                try
                {
                    /*送出訊息*/
                    m_SocketClient.SendTo(TxBuffer, m_IPPoint);
                    return (0);
                }
                catch
                {
                    return (-1);
                }
            }

            return (-1);           
        }
        #endregion

        #region 公用程式 Bytes、Stream 轉換
        /// <summary>
        /// 將 Byte陣列 轉為 Stream
        /// </summary>
        /// <returns>Stream</returns>
        public static Stream BytesToStream(byte[] bytes)
        {
            Stream stream = new MemoryStream(bytes);
            return stream;
        }

        public static Stream BytesToStream(byte[] bytes, int Length)
        {
            Stream stream = new MemoryStream(bytes, 0, Length);
            return stream;
        }
        /// <summary>
        /// 將 Stream 轉為 Byte陣列
        /// </summary>
        public static byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);

            /*將 stream 指針指向開頭*/
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }

        /// <summary>
        /// C# byte[]合併
        /// </summary>
        /// <returns>合併後的Byte[]</returns>
        private byte[] CombomBinaryArray(byte[] srcArray1, byte[] srcArray2)
        {
            //根据要合併的两Byte[]數量新建一個Byte[]
            byte[] newArray = new byte[srcArray1.Length + srcArray2.Length];

            Array.Copy(srcArray1, 0, newArray, 0, srcArray1.Length);
            Array.Copy(srcArray2, 0, newArray, srcArray1.Length, srcArray2.Length);
            return newArray;
        }






        #endregion

        /* 建構式 */
        public jUdpServer(object Owner, string IP, int APort)
        {
            mOwner = Owner;
            ServerPort = APort;
            ServerIP = IP;         
        }
        public jUdpServer(object Owner, int APort)
        {
            mOwner = Owner;
            ServerPort = APort;
            ServerIP = "0.0.0.0";
        }
        ~jUdpServer()
        {
            try { mSocketServer.Disconnect(true); }
            catch { }
            try { mSocketServer.Close(); }
            catch { }
        }

        /* 欄位 */
        // private bool mEnabled = false;
        private SetUdpReceived mSetUdpReceivedDlg; // 委派欄位
        private object mOwner; // 儲存擁有者
        private byte[] mRecvBuffer = new byte[10240]; // 接收資料的緩衝區
        private int mRecvBufferSize = 10240; // 接收資料的緩衝區大小
        private EndPoint mRemotePoint = new IPEndPoint(IPAddress.Any, 0); // 初始化遠端IP和 Port端點物件
        private Socket mSocketServer;// = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // 本機端 Socket物件       
       
        /* 屬性 */
        public string ServerIP { get; set; }
        public int ServerPort { get; set; }
        //public bool Enabled
        //{
        //    get { return mEnabled; }
        //    set
        //    {
        //        StartListen();
        //        mEnabled = value;
        //    }
        //}
        public int RecvBufferSize
        {
            get { return mRecvBufferSize; }
            set
            {
                if (mRecvBufferSize != value)
                {
                    mRecvBuffer = new byte[value];
                    mRecvBufferSize = value;
                }
            }
        }

        /* 方法 */       
        private void DoUdpReceivedText(Stream msg, IPEndPoint ipend)// 委派處理函式
        {
            UdpEventArgs e = new UdpEventArgs(msg, ipend);

            if (UdpReceived != null) //. 當事件變數不為 null 則執行之
            {
                UdpReceived(this, e);
            }
        }
        private void EndRecvCallBack(IAsyncResult result)// 非同步接收資料的回呼
        {
            try
            {
                /*傳回非同步物件*/
                Socket mResultSocket = result.AsyncState as Socket;

                /*呼叫 EndReceiveFrom 非同步接收*/
                int mRecvBytes = mResultSocket.EndReceiveFrom(result, ref mRemotePoint);

                /*將資料置入Stream */
                Stream mStream = BytesToStream(mRecvBuffer, mRecvBytes);

                /* Invoke */
                ((System.Windows.Forms.Control)mOwner).Invoke(
                    mSetUdpReceivedDlg,
                    mStream,
                    (IPEndPoint)mRemotePoint
                  ); //.. List<byte>

            }
            catch (Exception ex)
            {
                //((System.Windows.Forms.Control)m_Owner).Invoke(m_SetUdpReceivedDlg, ex.Message); //??????
            }
            finally
            {
                /*重新呼叫非同步接收*/
                mSocketServer.BeginReceiveFrom(
                    mRecvBuffer,
                    0,
                    mRecvBuffer.Length,
                    SocketFlags.None,
                    ref mRemotePoint,
                    new AsyncCallback(EndRecvCallBack),
                    mSocketServer
                  );
            }

        }
        public void StartListen()
        {
            // 開啟伺服器的 "ServerPort" 連接埠,用來接收任何傳送到本機的訊息。
            //IPEndPoint ipep = new IPEndPoint(IPAddress.Any, ServerPort);
            IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ServerIP), ServerPort);

            // 建立接收的 Socket,並使用 Udp 的 Datagram 方式接收。
            mSocketServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            // 綁定 Socket (newsock) 與 IPEndPoint (ipep),讓 Socket 接收 4001 埠的訊息。
            mSocketServer.Bind(ipep);
           
            mSetUdpReceivedDlg = DoUdpReceivedText; /*設定委派處理函式*/

            //..啟動非同步接受資料
            mSocketServer.BeginReceiveFrom(
                mRecvBuffer,
                0,
                mRecvBuffer.Length,
                SocketFlags.None,
                ref mRemotePoint,
                new AsyncCallback(EndRecvCallBack),
                mSocketServer
              );
        }

        /* 簽章 */
        private delegate void SetUdpReceived(Stream msg, IPEndPoint ipend);// 委派宣告
       
        /* 事件 */
        public event UdpEventHandler UdpReceived; // UDP Received 事件       
    }

    /// <summary>
    /// 定義專用事件參數類別
    /// </summary>
    public class UdpEventArgs : EventArgs
    {
        private IPEndPoint mIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
        private Stream mMSG = new MemoryStream();
        public UdpEventArgs(Stream msg, IPEndPoint ipend)
        {
            MSG = msg;
            mIpEndPoint.Address = ipend.Address;
            mIpEndPoint.Port = ipend.Port;
        }
        public IPEndPoint EndPoint
        {
            get { return mIpEndPoint; }
            private set { mIpEndPoint = value; }
        }
        public Stream MSG
        {
            get { return mMSG; }
            private set { mMSG = value; }
        }
    }

   
}