与众不同 windows phone (33) - Communication(通信)之源特定组播 SSM(Source Specific Multicast)

原文: 与众不同 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
[源码下载]

你可能感兴趣的:(windows phone)