與眾不同 windows phone (32) - Communication(通信)之任意源組播 ASM(Any Source Multicast)
作者:webabcd
介紹
與眾不同 windows phone 7.5 (sdk 7.1) 之通信
- 實現“任意源多播” - ASM(Any Source Multicast)
示例
實現 ASM 信道
UdpAnySourceMulticastChannel.cs
/* * 實現一個 ASM 信道(即 ASM 幫助類),供外部調用 * * * 通過 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 - 發出的信息是否需要傳給自己 * */ 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 Demo.Communication.SocketClient { public class UdpAnySourceMulticastChannel : IDisposable { // ASM 客戶端 private UdpAnySourceMulticastClient _client; // 接收信息的緩沖區 private byte[] _buffer; // 此客戶端是否加入了多播組 private bool _isJoined; /// <summary> /// 構造函數 /// </summary> /// <param name="groupAddress">多播組地址</param> /// <param name="port">多播組的端口</param> /// <param name="maxMessageSize">接收信息的緩沖區大小</param> /// <remarks> /// 注:udp 報文(Datagram)的最大長度為 65535(包括報文頭) /// </remarks> 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(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); _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); } } // 關閉 ASM 信道 public void Close() { _isJoined = false; OnClosing(); Dispose(); } public void Dispose() { if (_client != null) _client.Dispose(); } } }
演示 ASM
AnySourceMulticast.xaml
<phone:PhoneApplicationPage x:Class="Demo.Communication.SocketClient.AnySourceMulticast" 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" /> <TextBox x:Name="txtName" /> <TextBox x:Name="txtInput" KeyDown="txtInput_KeyDown" /> <Button x:Name="btnSend" Content="發送" Click="btnSend_Click" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
AnySourceMulticast.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 Microsoft.Phone.Controls; using System.Windows.Navigation; namespace Demo.Communication.SocketClient { public partial class AnySourceMulticast : PhoneApplicationPage { // 實例化自定義的 ASM 信道 private UdpAnySourceMulticastChannel _channel; public AnySourceMulticast() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { txtName.Text = "匿名" + new Random().Next(1000, 9999).ToString(); // 多播組地址是必須介於 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 UdpAnySourceMulticastChannel(IPAddress.Parse("224.0.1.1"), 3368, 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) { _channel.Send(string.Format("{0}: 進來了 - [{1}]", txtName.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}]", txtName.Text, DateTime.Now.ToString("HH:mm:ss"))); } private void btnSend_Click(object sender, RoutedEventArgs e) { SendMsg(); } private void txtInput_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { SendMsg(); this.Focus(); } } private void SendMsg() { _channel.Send(string.Format("{0}: {1} - [{2}]", txtName.Text, txtInput.Text, DateTime.Now.ToString("HH:mm:ss"))); txtInput.Text = ""; } } }
OK
[源碼下載]