稳扎稳打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 {  get set ; }
        
//  UDP 包的来源的 IPEndPoint 
         public  IPEndPoint Source {  get set ; }

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

        
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( 1000 9999 ).ToString();

            _channel 
=   new  UdpSingleSourceMulticastChannel(IPAddress.Parse( " 172.16.100.111 " ), IPAddress.Parse( " 224.0.0.1 " ),  3003 2048 ); 
            _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
[源码下载]

你可能感兴趣的:(silverlight)