稳扎稳打Silverlight(54) - 4.0通信之对UDP协议的支持: 通过 UdpAnySourceMulticastClient 实现 ASM(Any Source Multicast),即“任意源多播”

[索引页]
[源码下载]


稳扎稳打Silverlight(54) - 4.0通信之对UDP协议的支持: 通过 UdpAnySourceMulticastClient 实现 ASM(Any Source Multicast),即“任意源多播”



作者:webabcd


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

  • UdpAnySourceMulticastClient - 一个发送信息到多播组并从任意源接收多播信息的客户端,即 ASM 客户端



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


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

代码
// 启动多播的安全策略服务
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.AnySourceConfiguration.Add(
"*"new MulticastResource(IPAddress.Parse("224.0.0.1"), 3006)); // 配置 ASM 的安全策略

    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;
        }
    }
}


UdpAnySourceMulticastChannel.cs

代码
/*
 * 通过 UdpAnySourceMulticastClient 实现 ASM(Any Source Multicast),即“任意源多播”
 * 多播组基于 IGMP(Internet Group Management Protocol),即“Internet组管理协议”
 * 
 * UdpAnySourceMulticastClient - 一个发送信息到多播组并从任意源接收多播信息的客户端,即 ASM 客户端
 *     BeginJoinGroup(), EndJoinGroup() - 加入多播组的异步方法
 *     BeginReceiveFromGroup(), EndReceiveFromGroup() - 从多播组接收信息的异步方法(可以理解为接收多播组内所有成员发送的信息)
 *     BeginSendToGroup(), EndSendToGroup() - 发送信息到多播组的异步方法(可以理解为发送信息到多播组内的全部成员)
 *     ReceiveBufferSize - 接收信息的缓冲区大小
 *     SendBufferSize - 发送信息的缓冲区大小
 *     
 *     BeginSendTo(), EndSendTo() - 发送信息到指定目标的异步方法
 *     BlockSource() - 阻止指定源,以便不再接收该源发来的信息
 *     UnblockSource() - 取消阻止指定源
 *     MulticastLoopback - 发出的信息是否需要传给自己
 * 
 * 本例为一个通过 UdpAnySourceMulticastClient 实现 ASM 客户端的帮助类
 
*/

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 UdpAnySourceMulticastChannel : IDisposable
    {
        
private UdpAnySourceMulticastClient _client;

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

        
/// <summary>
        
/// 构造函数
        
/// </summary>
        
/// <param name="groupAddress">多播组地址</param>
        
/// <param name="port">客户端端口</param>
        
/// <param name="maxMessageSize">接收信息的缓冲区大小</param>
        public UdpAnySourceMulticastChannel(IPAddress groupAddress, int port, int maxMessageSize)
        {
            _buffer 
= new byte[maxMessageSize];
            
// 实例化 ASM 客户端,需要指定的参数为:多播组地址;客户端端口
            _client = new UdpAnySourceMulticastClient(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.BeginSendToGroup(data, 
0, data.Length,
                    result 
=>
                    {
                        _client.EndSendToGroup(result);
                    }, 
null);
            }
        }

        
/// <summary>
        
/// 从多播组接收信息,即接收多播组内所有成员发送的信息
        
/// </summary>
        private void Receive()
        {
            
if (_isJoined)
            {
                Array.Clear(_buffer, 
0, _buffer.Length);

                _client.BeginReceiveFromGroup(_buffer, 
0, _buffer.Length,
                    result 
=>
                    {
                        IPEndPoint source;
                        _client.EndReceiveFromGroup(result, 
out source);
                        Deployment.Current.Dispatcher.BeginInvoke(
                            () 
=>
                            {
                                OnReceived(source, _buffer);
                                Receive();
                            });
                    }, 
null);
            }
        }

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


UdpAnySourceMulticastClientDemo.xaml

代码
<navigation:Page x:Class="Silverlight40.Communication.UdpAnySourceMulticastClientDemo" 
           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
="UdpAnySourceMulticastClientDemo 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>


UdpAnySourceMulticastClientDemo.xaml.cs

代码
/*
 * 用于演示 ASM 的客户端
 
*/

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 UdpAnySourceMulticastClientDemo : Page
    {
        
private UdpAnySourceMulticastChannel _channel;

        
public UdpAnySourceMulticastClientDemo()
        {
            InitializeComponent();
        }

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

            _channel 
= new UdpAnySourceMulticastChannel(IPAddress.Parse("224.0.0.1"), 30062048); 
            _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)
        {
            _channel.Send(
string.Format("{0}: 进来了 - [{1}]", txtUserName.Text, DateTime.Now.ToString("HH:mm:ss")));
        }

        
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)
        {
            _channel.Send(
string.Format("{0}: 离开了 - [{1}]", txtUserName.Text, DateTime.Now.ToString("HH:mm:ss")));
        }

        
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
[源码下载]

posted @ 2010-09-20 08:25  webabcd  阅读(4596)  评论(19编辑  收藏  举报