zoukankan      html  css  js  c++  java
  • 与众不同 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
    [源码下载]

  • 相关阅读:
    对svn分支合并类型和深度的理解
    SVN中trunk,branches,tags用法详解
    如何从dump中查找ASP.NET Session的数据【转】
    c++学习笔记
    柳永教授嫖娼案庭审记录
    C++资源之不完全导引(转载)
    不讨老婆之“不亦快哉”(三十三则)(李敖)
    在一个ajax extender 工程中实现多个 ajax extender 控件的方法
    Creating a new extender(zz)
    打标签
  • 原文地址:https://www.cnblogs.com/webabcd/p/2699511.html
Copyright © 2011-2022 走看看