基本原理: (1) 组通信(组播):一组进程之间的IPC问题。 组播在即时消息、群件、在线会议、交互式远程学习、实时在线拍卖等应用中非常有用。也用于出于容错目的而进行的服务复制。 单播:数据从源进程(发送者)发送到某个目标进程(接收者)。 将消息发送到单个接收者。一对一通信。 组播:将消息发送到多个接收者。一对多通信。 组播组:一组进程形成一个组播组。 (2)基本组播API必须提供: ① 加入组播组(join) ② 离开组播组(leave) ③ 向组播组发送数据(send) ④ 接收发往组播组的组播消息(receive) (3)基本组播是无连接且不可靠的通信;在不可靠组播系统中,不能保证信息安全传递到每个参与者 (4)可靠组播系统保证发往组播组的每个消息被正确传递到每个参与者。可根据所支持的消息传递顺序对可靠组播进一步分类: ① 无序组播可将消息按任何顺序传递到每个参与者 ② FIFO组播保持发送者的发送顺序将消息传递到每个参与者 ③ 因果组播保持消息之间的因果关系(因果关系:Mi→Mj,传递性) ④ 原子组播按相同顺序将消息传递到所有成员 (5)IP组播地址使用D类地址和UDP端口的组合。D类IP地址由IANA管理和分配。组播应用可使用静态D类地址、运行时获得临时地址或任一未分配地址。下面是C#的具体实现: 使用UDPClient 类, 超级传送门:c#UDPClient实现组播及实例
组播地址为 224.0.0.0 ~ 239.255.255.255,其中 224.0.0.0~224.255.255.255 不建议在用户程序中使用,因为它们一般都有特殊用途。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.Threading;
namespace Test { class Program { static void Main(string[] args) { UdpClient client = new UdpClient(5566); client.JoinMulticastGroup(IPAddress.Parse("234.5.6.7")); IPEndPoint multicast = new IPEndPoint(IPAddress.Parse("234.5.6.7"), 7788); byte[] buf = Encoding.Default.GetBytes("Hello from multicast"); Thread t = new Thread(new ThreadStart(RecvThread)); t.IsBackground = true; t.Start(); while (true) { client.Send(buf, buf.Length, multicast); Thread.Sleep(1000); } }
tcp是面向连接的,一次只能连接一个端口upd是面向非连接的,所以不能发送完直接接收,需要做个udp侦听来接收对方发来的消息
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;namespace Mengsk.ERP.Broadcast
{
public class MessageCenter
{
/// <summary>
/// 唯一实例,类加载器保证生成唯一的
/// </summary>
private static readonly MessageCenter instance = new MessageCenter(); public static MessageCenter Instance { get { return instance; } } /// <summary>
/// 通信的通信的udp商品
/// </summary>
private Socket udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); /// <summary>
/// 获取远程IP,商品的参数
/// </summary>
private EndPoint remoteIP = new IPEndPoint(IPAddress.Any, 3666); /// <summary>
/// 接收数据的本地商品
/// </summary>
private EndPoint listenSocket = new IPEndPoint(IPAddress.Any, 3666); /// <summary>
/// 需要组播的网段,一台电脑可能有多块网卡,
/// </summary>
private EndPoint[] broadcastEndPoint = null; private byte[] reciveBuf = new byte[1024 * 1024]; private byte[] sendBuf = new byte[1024 * 1024]; private BinaryFormatter binaryFormatter = new BinaryFormatter(); public event EventHandler<MessageArrviedEventArgs> MessageArrived; public MessageCenter()
{
//绑定通信商品
this.udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
this.udpSocket.Bind(listenSocket);
//获取本地所有网络接口,并生成组播地址
this.broadcastEndPoint = Dns.GetHostAddresses(Dns.GetHostName()).Where(ip => ip.AddressFamily == AddressFamily.InterNetwork).Select(
ipa => new IPEndPoint(IPAddress.Parse(ipa.ToString().Substring(0, ipa.ToString().LastIndexOf('.')) + ".255"), 3666)).ToArray();
} /// <summary>
/// udp收到数据的回调
/// </summary>
/// <param name="ar"></param>
private void DataReciveCallback(IAsyncResult ar)
{
try
{
int ret = this.udpSocket.EndReceiveFrom(ar, ref this.remoteIP);
if (ret <= 0)
{
return;
}
MemoryStream ms = new MemoryStream(this.reciveBuf, 0, ret);
Message m = this.binaryFormatter.Deserialize(ms) as Message;
if (this.MessageArrived != null)
{
this.MessageArrived(this, new MessageArrviedEventArgs(m));
}
//开始新的接收
this.udpSocket.BeginReceiveFrom(this.reciveBuf, 0, this.reciveBuf.Length, SocketFlags.None, ref this.remoteIP, this.DataReciveCallback, null);
}
catch
{
this.udpSocket.Close();
}
} /// <summary>
/// 开始接收数据
/// </summary>
public void Start()
{
this.udpSocket.BeginReceiveFrom(this.reciveBuf, 0, this.reciveBuf.Length, SocketFlags.None, ref this.remoteIP, this.DataReciveCallback, null);
} /// <summary>
/// 停止接收数据
/// </summary>
public void Stop()
{
this.udpSocket.Close();
} /// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
public void SendMessage(Message message)
{
//序列化数据
MemoryStream ms = new MemoryStream(this.sendBuf);
this.binaryFormatter.Serialize(ms, message);
var buf = ms.ToArray(); //向计算中的每一个网络接口广播数据
foreach (EndPoint ep in this.broadcastEndPoint)
{
this.udpSocket.SendTo(buf, (int)ms.Position, SocketFlags.None, ep);
}
}
}
}
(1)
组通信(组播):一组进程之间的IPC问题。
组播在即时消息、群件、在线会议、交互式远程学习、实时在线拍卖等应用中非常有用。也用于出于容错目的而进行的服务复制。
单播:数据从源进程(发送者)发送到某个目标进程(接收者)。
将消息发送到单个接收者。一对一通信。
组播:将消息发送到多个接收者。一对多通信。
组播组:一组进程形成一个组播组。
(2)基本组播API必须提供:
① 加入组播组(join)
② 离开组播组(leave)
③ 向组播组发送数据(send)
④ 接收发往组播组的组播消息(receive)
(3)基本组播是无连接且不可靠的通信;在不可靠组播系统中,不能保证信息安全传递到每个参与者
(4)可靠组播系统保证发往组播组的每个消息被正确传递到每个参与者。可根据所支持的消息传递顺序对可靠组播进一步分类:
① 无序组播可将消息按任何顺序传递到每个参与者
② FIFO组播保持发送者的发送顺序将消息传递到每个参与者
③ 因果组播保持消息之间的因果关系(因果关系:Mi→Mj,传递性)
④ 原子组播按相同顺序将消息传递到所有成员
(5)IP组播地址使用D类地址和UDP端口的组合。D类IP地址由IANA管理和分配。组播应用可使用静态D类地址、运行时获得临时地址或任一未分配地址。下面是C#的具体实现:
使用UDPClient 类, 超级传送门:c#UDPClient实现组播及实例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Test
{
class Program
{
static void Main(string[] args)
{
UdpClient client = new UdpClient(5566);
client.JoinMulticastGroup(IPAddress.Parse("234.5.6.7"));
IPEndPoint multicast = new IPEndPoint(IPAddress.Parse("234.5.6.7"), 7788);
byte[] buf = Encoding.Default.GetBytes("Hello from multicast");
Thread t = new Thread(new ThreadStart(RecvThread));
t.IsBackground = true;
t.Start();
while (true)
{
client.Send(buf, buf.Length, multicast);
Thread.Sleep(1000);
}
}
static void RecvThread()
{
UdpClient client = new UdpClient(7788);
client.JoinMulticastGroup(IPAddress.Parse("234.5.6.7"));
IPEndPoint multicast = new IPEndPoint(IPAddress.Parse("234.5.6.7"), 5566);
while (true)
{
byte[] buf = client.Receive(ref multicast);
string msg = Encoding.Default.GetString(buf);
Console.WriteLine(msg);
}
}
}
}