zoukankan      html  css  js  c++  java
  • 稳扎稳打Silverlight(55) 4.0通信之对UDP协议的支持: 通过 UdpSingleSourceMulticastClient 实现 SSM(Source Specific Multicast),即“源特定多播”

    [索引页]
    [源码下载]


    稳扎稳打Silverlight(55) - 4.0通信之对UDP协议的支持: 通过 UdpSingleSourceMulticastClient 实现 SSM(Source Specific Multicast),即“源特定多播”



    作者:webabcd


    介绍
    Silverlight 4.0 对 UDP 协议的支持:

    • UdpSingleSourceMulticastClient - 一个从单一源接收多播信息的客户端,即 SSM 客户端



    在线DEMO
    http://www.cnblogs.com/webabcd/archive/2010/08/09/1795417.html


    示例
    演示如何通过 UdpSingleSourceMulticastClient 实现 SSM
    1、服务端
    Form1.cs

    代码
    // 启动用于演示 SSM 的 Socket 服务(基于 UDP 协议)
    private void LaunchSocketUdp()
    {
        
    // 服务端的 IPEndPoint
        IPEndPoint serverPoint = new IPEndPoint(IPAddress.Any, 3004);
        
    // 广播地址的 IPEndPoint(255.255.255.255)
        IPEndPoint broadcastPoint = new IPEndPoint(IPAddress.Broadcast, 3003);

        
    // 根据服务端的 IPEndPoint 创建服务端的 UDP 对象
        UdpClient serverUdp = new UdpClient(serverPoint);
        ShowMessage(
    "演示 SSM 的 Socket 服务已启动(基于 UDP 协议)");

                
        
    // 每 3 表广播一次
        var timer = new System.Timers.Timer();
        timer.Interval 
    = 3000d;
        timer.Elapsed 
    += delegate
        {
            
    string msg = string.Format("{0}: {1} - [{2}]", Dns.GetHostName(), "广播内容", DateTime.Now.ToString("HH:mm:ss"));
            
    byte[] data = Encoding.UTF8.GetBytes(msg);

            
    // 发送广播(分别需要指定:广播内容;广播内容的字节数;广播地址的 IPEndPoint)
            serverUdp.Send(data, data.Length, broadcastPoint);
        };
        timer.Start();


        
    // 接收客户端发过来的信息
        var thread = new System.Threading.Thread(() =>
        {
            
    while (true)
            {
                IPEndPoint clientPoint 
    = null;
                
    // 接收客户端传来的信息,并获取客户端的 IPEndPoint
                byte[] receivedBytes = serverUdp.Receive(ref clientPoint);
                
    string receivedData = Encoding.UTF8.GetString(receivedBytes);
                
    string message = string.Format("{0} - 来自:{1}", receivedData, clientPoint.ToString());

                _syncContext.Post(
    delegate { ShowMessage(message); }, null);
            }
        });
        thread.Start();
    }

    // 启动多播的安全策略服务
    private void LaunchMulticastPolicyServer()
    {
        
    /*
            * Silverlight 程序加入多播组之前,会通过 UDP 端口 9430 发送初始消息到多播组,然后服务端返回相应的安全策略(详见文档)
            * 为了方便下发安全策略,可以引用 Microsoft.Silverlight.PolicyServers.dll 程序集,其封装了相关的方法
            
    */

        
    // 本例的安全策略配置结果为:授权通过 UDP 端口 3003 问多播组 224.0.0.1,授权通过 UDP 端口 3006 问多播组 224.0.0.1
        MulticastPolicyConfiguration config = new MulticastPolicyConfiguration();
        config.SingleSourceConfiguration.Add(
    "*"new MulticastResource(IPAddress.Parse("224.0.0.1"), 3003)); // 配置 SSM 的安全策略

        MulticastPolicyServer server 
    = new MulticastPolicyServer(config);
        server.Start();

        ShowMessage(
    "多播的安全策略服务已启动");
    }



    2、客户端
    UdpPacketEventArgs.cs

    代码
    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;

    namespace Silverlight40.Communication
    {
        
    public class UdpPacketEventArgs : EventArgs
        {
            
    // UDP 包的内容
            public string Message { getset; }
            
    // UDP 包的来源的 IPEndPoint 
            public IPEndPoint Source { getset; }

            
    public UdpPacketEventArgs(byte[] data, IPEndPoint source)
            {
                
    this.Message = System.Text.Encoding.UTF8.GetString(data, 0, data.Length);
                
    this.Source = source;
            }
        }
    }


    UdpSingleSourceMulticastChannel.cs

    代码
    /*
     * 通过 UdpSingleSourceMulticastClient 实现 SSM(Source Specific Multicast),即“源特定多播”
     * 多播组基于 IGMP(Internet Group Management Protocol),即“Internet组管理协议”
     * 
     * UdpSingleSourceMulticastClient - 一个从单一源接收多播信息的客户端,即 SSM 客户端
     *     BeginJoinGroup(), EndJoinGroup() - 加入“源”的异步方法
     *     BeginReceiveFromSource(), EndReceiveFromSource() - 从“源”接收信息的异步方法
     *     BeginSendToSource(), EndSendToSource() - 发送信息到“源”的异步方法
     *     ReceiveBufferSize - 接收信息的缓冲区大小
     *     SendBufferSize - 发送信息的缓冲区大小
     *     
     * 本例为一个通过 UdpSingleSourceMulticastClient 实现 SSM 客户端的帮助类
     
    */

    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.Text;
    using System.Net.Sockets;

    namespace Silverlight40.Communication
    {
        
    public class UdpSingleSourceMulticastChannel : IDisposable
        {
            
    // 多播源的端口
            private int _serverPort = 3004;

            
    private UdpSingleSourceMulticastClient _client;
            
    // 接收信息的缓冲区
            private byte[] _buffer;
            
    // 此客户端是否加入了多播组
            private bool _isJoined;
            
    // 多播源的地址
            private IPAddress _sourceAddress;

            
    /// <summary>
            
    /// 构造函数
            
    /// </summary>
            
    /// <param name="sourceAddress">“源”的地址</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(
    thisnew 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);
                }
            } 

            
    public void Close()
            {
                _isJoined 
    = false;
                OnClosing();
                Dispose();
            }

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

                    
    // 需要指定多播源的端口
                    _client.BeginSendToSource(data, 0, data.Length, _serverPort,
                        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);
                }
            }

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


    UdpSingleSourceMulticastClientDemo.xaml

    代码
    <navigation:Page x:Class="Silverlight40.Communication.UdpSingleSourceMulticastClientDemo" 
               xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
               xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml" 
               xmlns:d
    ="http://schemas.microsoft.com/expression/blend/2008"
               xmlns:mc
    ="http://schemas.openxmlformats.org/markup-compatibility/2006"
               xmlns:navigation
    ="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
               Title
    ="UdpSingleSourceMulticastClientDemo Page">
        
    <Grid x:Name="LayoutRoot">
            
            
    <Grid.ColumnDefinitions>
                
    <ColumnDefinition Width="80" />
                
    <ColumnDefinition Width="*" />
                
    <ColumnDefinition Width="60" />
            
    </Grid.ColumnDefinitions>
            
    <Grid.RowDefinitions>
                
    <RowDefinition Height="*" />
                
    <RowDefinition Height="40" />
            
    </Grid.RowDefinitions>

            
    <ListBox Name="lstAllMsg" Grid.ColumnSpan="3" Margin="6" />
            
    <TextBox Name="txtUserName" Grid.Row="1" Grid.Column="0" Margin="6" />
            
    <TextBox Name="txtSendMsg" Grid.Row="1" Grid.Column="1" TextWrapping="Wrap" Margin="6" KeyDown="txtMsg_KeyDown" />
            
    <Button Name="btnSend" Grid.Row="1" Grid.Column="2" Margin="6" Content="发送" Click="btnSend_Click" />
            
        
    </Grid>
    </navigation:Page>


    UdpSingleSourceMulticastClientDemo.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 System.Windows.Navigation;

    namespace Silverlight40.Communication
    {
        
    public partial class UdpSingleSourceMulticastClientDemo : Page
        {
            
    private UdpSingleSourceMulticastChannel _channel;

            
    public UdpSingleSourceMulticastClientDemo()
            {
                InitializeComponent();
            }

            
    protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                txtUserName.Text 
    = "匿名" + new Random().Next(10009999).ToString();

                _channel 
    = new UdpSingleSourceMulticastChannel(IPAddress.Parse("172.16.100.111"), IPAddress.Parse("224.0.0.1"), 30032048); 
                _channel.Opening 
    += new EventHandler(_channel_Opening);
                _channel.Received 
    += new EventHandler<UdpPacketEventArgs>(_channel_Received);
                _channel.Closing 
    += new EventHandler(_channel_Closing);

                Application.Current.Exit 
    += new EventHandler(Current_Exit);

                _channel.Open();
            }

            
    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"已经断开多播源");
            }

            
    void Current_Exit(object sender, EventArgs e)
            {
                _channel.Dispose();
            }

            
    private void btnSend_Click(object sender, RoutedEventArgs e)
            {
                SendMsg();
            }

            
    private void txtMsg_KeyDown(object sender, KeyEventArgs e)
            {
                
    if (e.Key == Key.Enter)
                    SendMsg();
            }

            
    private void SendMsg()
            {
                _channel.Send(
    string.Format("{0}: {1} - [{2}]", txtUserName.Text, txtSendMsg.Text, DateTime.Now.ToString("HH:mm:ss")));
                txtSendMsg.Text 
    = "";
            }
        }
    }



    OK
    [源码下载]

  • 相关阅读:
    类加载机制深度解析
    Mysql索引数据结构详解(1)
    深入理解mysql锁与事务隔离级别
    关于redis HSCAN count参数不生效的问题
    在idea的java开发中字符串length()方法获取长度与赋值不符的问题
    在网页中使用超链接来打开本地应用(可传参数)
    断言(assert)简介
    9. Palindrome Number
    四、MapReduce
    三、HDFS——Hadoop分布式文件系统
  • 原文地址:https://www.cnblogs.com/webabcd/p/1836732.html
Copyright © 2011-2022 走看看