[源码下载]
作者: webabcd
介绍
Silverlight 4.0 对 UDP 协议的支持:
在线DEMO
http://www.cnblogs.com/webabcd/archive/2010/08/09/1795417.html
示例
演示如何通过 UdpSingleSourceMulticastClient 实现 SSM
1、服务端
Form1.cs
2、客户端
UdpPacketEventArgs.cs
UdpSingleSourceMulticastChannel.cs
UdpSingleSourceMulticastClientDemo.xaml
UdpSingleSourceMulticastClientDemo.xaml.cs
OK
[源码下载]
稳扎稳打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( " 多播的安全策略服务已启动 " );
}
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;
}
}
}
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, _serverPort,
result =>
{
_client.EndSendToSource(result);
}, null );
}
}
/// <summary>
/// 接收从“源”发过来的广播信息
/// </summary>
private void Receive()
{
if (_isJoined)
{
Array.Clear(_buffer, _buffer.Length);
_client.BeginReceiveFromSource(_buffer, _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();
}
}
}
* 通过 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, _serverPort,
result =>
{
_client.EndSendToSource(result);
}, null );
}
}
/// <summary>
/// 接收从“源”发过来的广播信息
/// </summary>
private void Receive()
{
if (_isJoined)
{
Array.Clear(_buffer, _buffer.Length);
_client.BeginReceiveFromSource(_buffer, _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 >
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, " 已经断开多播源 " );
}
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 = "" ;
}
}
}
* 用于演示 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, " 已经断开多播源 " );
}
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
[源码下载]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。