與眾不同 windows phone (33) - Communication(通信)之源特定組播 SSM(Source Specific Multicast)


[索引頁]
[源碼下載]


與眾不同 windows phone (33) - Communication(通信)之源特定組播 SSM(Source Specific Multicast)



作者:webabcd


介紹
與眾不同 windows phone 7.5 (sdk 7.1) 之通信

  • 實現“源特定多播” - SSM(Source Specific Multicast)



示例
1、服務端
Main.cs

/*
 * 此服務會定時向指定的多播組發送消息,用於演示 SSM
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;

namespace SocketServerSSM
{
    public partial class Main : Form
    {
        System.Threading.SynchronizationContext _syncContext;

        public Main()
        {
            InitializeComponent();

            LaunchSocketUdp();
        }

        private void LaunchSocketUdp()
        {
            _syncContext = System.Threading.SynchronizationContext.Current;

            // 定義 Source Specific Multicast 中的 Source,即 SSM 客戶端僅接收此 Source 發送到多播組的數據
            IPEndPoint sourcePoint = new IPEndPoint(IPAddress.Any, 3370);

            // 定義多播組
            IPEndPoint multicastPoint = new IPEndPoint(IPAddress.Parse("224.0.1.2"), 3369);

            UdpClient sourceUdp = new UdpClient(sourcePoint);
            ShowMessage("用於演示 SSM 的 Socket 服務已啟動,每 3 秒向多播組發送一次信息");


            // 每 3 秒向多播組發送一次信息
            var timer = new System.Timers.Timer();
            timer.Interval = 3000d;
            timer.Elapsed += delegate
            {
                string msg = string.Format("{0} - {1}", Dns.GetHostName(), DateTime.Now.ToString("HH:mm:ss"));
                byte[] data = Encoding.UTF8.GetBytes(msg);

                sourceUdp.Send(data, data.Length, multicastPoint);
            };
            timer.Start();
        }

        public void ShowMessage(string msg)
        {
            txtMsg.Text += msg + "\r\n";
        }
    }
}

 

2、客戶端
實現 SSM 信道
UdpSingleSourceMulticastChannel.cs

/*
 * 實現一個 SSM 信道(即 SSM 幫助類),供外部調用
 * 
 * 
 * 通過 UdpSingleSourceMulticastClient 實現 SSM(Source Specific Multicast),即“源特定多播”
 * 多播組基於 IGMP(Internet Group Management Protocol),即“Internet組管理協議”
 * 
 * UdpSingleSourceMulticastClient - 一個從單一源接收多播信息的客戶端,即 SSM 客戶端
 *     BeginJoinGroup(), EndJoinGroup() - 加入“源”的異步方法
 *     BeginReceiveFromSource(), EndReceiveFromSource() - 從“源”接收信息的異步方法
 *     BeginSendToSource(), EndSendToSource() - 發送信息到“源”的異步方法
 *     ReceiveBufferSize - 接收信息的緩沖區大小
 *     SendBufferSize - 發送信息的緩沖區大小
 */

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using System.Net.Sockets;
using System.Text;

namespace Demo.Communication.SocketClient
{
    public class UdpSingleSourceMulticastChannel : IDisposable
    {
        // SSM 客戶端
        private UdpSingleSourceMulticastClient _client;
        
        // “源”的地址
        private IPAddress _sourceAddress;

        // 接收信息的緩沖區
        private byte[] _buffer;
        // 此客戶端是否加入了多播組
        private bool _isJoined;

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="sourceAddress">SSM 的“源”的地址</param>
        /// <param name="groupAddress">多播組的地址</param>
        /// <param name="port">多播組的端口</param>
        /// <param name="maxMessageSize">接收信息的緩沖區大小</param>
        public UdpSingleSourceMulticastChannel(IPAddress sourceAddress, IPAddress groupAddress, int port, int maxMessageSize)
        {
            _sourceAddress = sourceAddress;
            _buffer = new byte[maxMessageSize];

            // 實例化 SSM 客戶端,需要指定的參數為:“源”的地址;多播組的地址;多播組的端口
            _client = new UdpSingleSourceMulticastClient(sourceAddress, groupAddress, port);
        }

        // 收到多播信息后觸發的事件
        public event EventHandler<UdpPacketEventArgs> Received;
        private void OnReceived(IPEndPoint source, byte[] data)
        {
            var handler = Received;
            if (handler != null)
                handler(this, new UdpPacketEventArgs(data, source));
        }

        // 加入多播組后觸發的事件
        public event EventHandler Opening;
        private void OnOpening()
        {
            var handler = Opening;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }

        // 斷開多播組后觸發的事件
        public event EventHandler Closing;
        private void OnClosing()
        {
            var handler = Closing;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }

        /// <summary>
        /// 加入多播組
        /// </summary>
        public void Open()
        {
            if (!_isJoined)
            {
                _client.BeginJoinGroup(
                    result =>
                    {
                        _client.EndJoinGroup(result);
                        _isJoined = true;
                        Deployment.Current.Dispatcher.BeginInvoke(
                            () =>
                            {
                                OnOpening();
                                Receive();
                            });
                    }, null);
            }
        }

        /// <summary>
        /// 發送信息到“源”
        /// </summary>
        public void Send(string msg)
        {
            if (_isJoined)
            {
                byte[] data = Encoding.UTF8.GetBytes(msg);

                // 需要指定“源”的端口
                int sourcePort = 100;
                _client.BeginSendToSource(data, 0, data.Length, sourcePort,
                    result =>
                    {
                        _client.EndSendToSource(result);
                    }, null);
            }
        }

        /// <summary>
        /// 接收從多播組發過來的信息,即“源”發送給多播組的信息
        /// </summary>
        private void Receive()
        {
            if (_isJoined)
            {
                Array.Clear(_buffer, 0, _buffer.Length);

                _client.BeginReceiveFromSource(_buffer, 0, _buffer.Length,
                    result =>
                    {
                        int sourcePort;
                        // 接收到多播信息后,可獲取到“源”的端口
                        _client.EndReceiveFromSource(result, out sourcePort);
                        Deployment.Current.Dispatcher.BeginInvoke(
                            () =>
                            {
                                OnReceived(new IPEndPoint(_sourceAddress, sourcePort), _buffer);
                                Receive();
                            });
                    }, null);
            }
        }

        // 關閉 SSM 信道
        public void Close()
        {
            _isJoined = false;
            OnClosing();
            Dispose();
        }

        public void Dispose()
        {
            if (_client != null)
                _client.Dispose();
        }
    }
}

演示 SSM
SourceSpecificMulticast.xaml

<phone:PhoneApplicationPage 
    x:Class="Demo.Communication.SocketClient.SourceSpecificMulticast"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <StackPanel HorizontalAlignment="Left">

            <ListBox Name="lstAllMsg" MaxHeight="400" />

        </StackPanel>
    </Grid>

</phone:PhoneApplicationPage>

SourceSpecificMulticast.xaml.cs

/*
 * 用於演示 SSM
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using System.Windows.Navigation;

namespace Demo.Communication.SocketClient
{
    public partial class SourceSpecificMulticast : PhoneApplicationPage
    {
        // 實例化自定義的 SSM 信道
        private UdpSingleSourceMulticastChannel _channel;

        public SourceSpecificMulticast()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // 多播組地址是必須介於 224.0.0.0 到 239.255.255.255 之間的 IP 地址,其中范圍介於 224.0.0.0 到 224.0.0.255 之間的多播地址是保留多播地址
            // 比如:224.0.0.0 是基址,224.0.0.1 是代表同一個物理網絡中所有系統的多播組地址,而 224.0.0.2 代表同一個物理網絡中的所有路由器
            _channel = new UdpSingleSourceMulticastChannel(IPAddress.Parse("192.168.8.217"), IPAddress.Parse("224.0.1.2"), 3369, 2048);
            _channel.Opening += new EventHandler(_channel_Opening);
            _channel.Received += new EventHandler<UdpPacketEventArgs>(_channel_Received);
            _channel.Closing += new EventHandler(_channel_Closing);

            _channel.Open();

            // 需要的使用,應該調用 Close()
            // _channel.Close();
        }

        void _channel_Opening(object sender, EventArgs e)
        {
            lstAllMsg.Items.Insert(0, "已經連上多播組,等待來自多播組的消息");
        }

        void _channel_Received(object sender, UdpPacketEventArgs e)
        {
            // 因為已經指定了接收信息的緩沖區大小是 2048 ,所以如果信息不夠 2048 個字節的的話,空白處均為空字節“\0”
            string message = string.Format("{0} - 來自:{1}", e.Message.TrimEnd('\0'), e.Source.ToString());
            lstAllMsg.Items.Insert(0, message);
        }

        void _channel_Closing(object sender, EventArgs e)
        {
            lstAllMsg.Items.Insert(0, "已經斷開多播組");
        }
    }
}



OK
[源碼下載]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM