title author date CreateTime categories
C# dotnet core 局域网组播方法
lindexi
2019-10-30 9:0:48 +0800
2019-10-29 12:2:46 +0800
dotnet C#

我在微软官网找到了用 C# 做 UDP 组播的方法,我优化一些逻辑,保留核心代码,然后加了一点封装

在使用之前需要注意的是组播可以用来做局域网传输,但是组播不是可靠的方案,随时可能因为路由器等发送失败或无法接收消息

使用组播的方法是创建 Socket 通过 UDP 向组播地址发送数据或从组播地址接收数据

可以作为组播的地址是 239.0.0.0~239.255.255.255 的范围,这个范围是局域网可用。但实际可用或不可用还需要靠实际的路由器

首先创建一个 Socket 然后绑定到端口

        private IPAddress LocalIpAddress { set; get; } = IPAddress.Any;

        private Socket MulticastSocket { get; }

        private const int MulticastPort = 15003;

        private void TryBindSocket()
{
for (var i = MulticastPort; i < 65530; i++)
{
try
{
EndPoint localEndPoint = new IPEndPoint(LocalIpAddress, i); MulticastSocket.Bind(localEndPoint);
return;
}
catch (SocketException e)
{
Console.WriteLine(e);
}
}
}

绑定的端口是用来接收的端口,所以绑定失败不会影响发送

绑定完成需要加入组播网络

                var multicastOption = new MulticastOption(MulticastAddress, IPAddress.Any);

                MulticastSocket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.AddMembership,
multicastOption); /// <summary>
/// 组播地址
/// <para/>
/// 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
/// <para/>
/// 224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet;
/// <para/>
/// 224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效;
/// <para/>
/// 239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。
/// </summary>
public IPAddress MulticastAddress { set; get; }

需要注意,上面代码的 LocalIpAddress 写的是 Any 也就是只有在默认的网卡是和其他设备网段才能访问

如果发现其他设备不能接收到信息,那么请修改 LocalIpAddress 为你设备的地址

接收方法和接收其他相同

        private void ReceiveBroadcastMessages()
{
// 接收需要绑定 MulticastPort 端口
var bytes = new byte[MaxByteLength];
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); try
{
while (true)
{
var length = MulticastSocket.ReceiveFrom(bytes, ref remoteEndPoint); Console.WriteLine(Encoding.UTF8.GetString(bytes, 0, length));
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}

接收和发送都是二进制

        /// <summary>
/// 发送组播
/// </summary>
/// <param name="message"></param>
public void SendBroadcastMessage(string message)
{
try
{
var endPoint = new IPEndPoint(MulticastAddress, MulticastPort);
var byteList = Encoding.UTF8.GetBytes(message); MulticastSocket.SendTo(byteList, endPoint);
}
catch (Exception e)
{
Console.WriteLine("\n" + e);
}
}

所有代码

    internal class PeerMulticastFinder : IDisposable
{
/// <inheritdoc />
public PeerMulticastFinder()
{
MulticastSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
MulticastAddress = IPAddress.Parse("230.138.100.2");
} /// <summary>
/// 寻找局域网设备
/// </summary>
public void FindPeer()
{
// 实际是反过来,让其他设备询问 StartMulticast(); var ipList = GetLocalIpList().ToList();
var message = string.Join(';',ipList);
SendBroadcastMessage(message);
// 先发送再获取消息,这样就不会收到自己发送的消息
ReceivedMessage += (s, e) => { Console.WriteLine($"找到 {e}"); };
} /// <summary>
/// 获取本地 IP 地址
/// </summary>
/// <returns></returns>
private IEnumerable<IPAddress> GetLocalIpList()
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
yield return ip;
}
}
} /// <summary>
/// 组播地址
/// <para/>
/// 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
/// <para/>
/// 224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet;
/// <para/>
/// 224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效;
/// <para/>
/// 239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。
/// </summary>
public IPAddress MulticastAddress { set; get; } private const int MulticastPort = 15003; /// <summary>
/// 启动组播
/// </summary>
public void StartMulticast()
{
try
{
// 如果首次绑定失败,那么将无法接收,但是可以发送
TryBindSocket(); // Define a MulticastOption object specifying the multicast group
// address and the local IPAddress.
// The multicast group address is the same as the address used by the server.
// 有多个 IP 时,指定本机的 IP 地址,此时可以接收到具体的内容
var multicastOption = new MulticastOption(MulticastAddress, IPAddress.Parse("172.18.134.16")); MulticastSocket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.AddMembership,
multicastOption);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
} Task.Run(ReceiveBroadcastMessages);
} /// <summary>
/// 收到消息
/// </summary>
public event EventHandler<string> ReceivedMessage; private void ReceiveBroadcastMessages()
{
// 接收需要绑定 MulticastPort 端口
var bytes = new byte[MaxByteLength];
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); try
{
while (!_disposedValue)
{
var length = MulticastSocket.ReceiveFrom(bytes, ref remoteEndPoint); OnReceivedMessage(Encoding.UTF8.GetString(bytes, 0, length));
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
} /// <summary>
/// 发送组播
/// </summary>
/// <param name="message"></param>
public void SendBroadcastMessage(string message)
{
try
{
var endPoint = new IPEndPoint(MulticastAddress, MulticastPort);
var byteList = Encoding.UTF8.GetBytes(message); if (byteList.Length > MaxByteLength)
{
throw new ArgumentException($"传入 message 转换为 byte 数组长度太长,不能超过{MaxByteLength}字节")
{
Data =
{
{ "message", message },
{ "byteList", byteList }
}
};
} MulticastSocket.SendTo(byteList, endPoint);
}
catch (Exception e)
{
Console.WriteLine("\n" + e);
}
} private IPAddress LocalIpAddress { set; get; } = IPAddress.Any; private Socket MulticastSocket { get; } private void TryBindSocket()
{
for (var i = MulticastPort; i < 65530; i++)
{
try
{
EndPoint localEndPoint = new IPEndPoint(LocalIpAddress, i); MulticastSocket.Bind(localEndPoint);
return;
}
catch (SocketException e)
{
Console.WriteLine(e);
}
}
} private const int MaxByteLength = 1024; #region IDisposable Support private bool _disposedValue = false; // 要检测冗余调用 private void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
} MulticastSocket.Dispose(); ReceivedMessage = null;
MulticastAddress = null; _disposedValue = true;
}
} // 添加此代码以正确实现可处置模式。
public void Dispose()
{
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
Dispose(true);
GC.SuppressFinalize(this);
} #endregion private void OnReceivedMessage(string e)
{
ReceivedMessage?.Invoke(this, e);
}
}

2019-10-30-C#-dotnet-core-局域网组播方法的更多相关文章

  1. dotnet core 获取 MacAddress 地址方法

    本文告诉大家如何在 dotnet core 获取 Mac 地址 因为在 dotnetcore 是没有直接和硬件相关的,所以无法通过 WMI 的方法获取当前设备的 Mac 地址 但是在 dotnet c ...

  2. 【2019.10.30】SDN上机第1次作业

    用字符命令搭建如下拓扑,要求写出命令 题目一: 字符命令如下: 题目二: 字符命令如下: 利用可视化工具搭建如下拓扑 要求支持OpenFlow 1.0 1.1 1.2 1.3,设置h1(10.0.0. ...

  3. 2019.10.30 csp-s模拟测试94 反思总结

    头一次做图巨的模拟题OWO 自从上一次听图巨讲课然后骗了小礼物以后一直对图巨印象挺好的233 T1: 对于XY取对数=Y*log(x) 对于Y!取对数=log(1*2*3*...*Y)=log1+lo ...

  4. dotnet core 通过 frp 发布自己的网站

    很多时候写出来的网站只能自己内网访问,本文告诉大家如何通过 Frp 将自己的 asp dotnet core 网站发布到外网,让小伙伴访问自己的网站 通过 frp 的方式,可以解决自己的服务器性能太差 ...

  5. asp dotnet core 支持客户端上传文件

    本文告诉大家如何在 asp dotnet core 支持客户端上传文件 新建一个 asp dotnet core 程序,创建一个新的类,用于给客户端上传文件的信息 public class Kanaj ...

  6. Java单播、组播(多播)、广播的简单实现

    简介 单播有TCP和UDP两种实现,组播(多播)和广播只有UDP一种实现.单播和广播基本一样,只是广播的数据包IP为广播IP.   单播 DatagramSocket和DatagramPacket 服 ...

  7. Alpha冲刺(7/10)——2019.4.30

    所属课程 软件工程1916|W(福州大学) 作业要求 Alpha冲刺(7/10)--2019.4.30 团队名称 待就业六人组 1.团队信息 团队名称:待就业六人组 团队描述:同舟共济扬帆起,乘风破浪 ...

  8. ubuntu15.10 或者 16.04 或者 ElementryOS 下使用 Dotnet Core

    这里我们不讲安装,缺少libicu52自行安装. 安装完成后使用dotnet restore或者build都会失败,一是报编译的dll不适合当前系统,二是编译到ubuntu16.04文件夹下会产生一些 ...

  9. 使用 dotnet core 和 Azure PaaS服务进行devOps开发(Web API 实例)

    作者:陈希章 发表于 2017年12月19日 引子 这一篇文章将用一个完整的实例,给大家介绍如何基于dotnet core(微软.NET的最新版本,支持跨平台,跨设备的应用开发,详情请参考 https ...

随机推荐

  1. HR招聘_(七)_招聘方法论(面试环节·动机判断)

    候选人选择一般会看硬性技能,软性技能,动机意愿三个方面的匹配程度,硬性技能主要指纵向的业务能力,部门面试官也会着重看这方面,软性技能包括沟通,情商,气质等.动机意愿非常重要,再优秀的如果没有意愿,动机 ...

  2. CSS hack处理

    css hack指各版本及各品牌浏览器之间对CSS解释后出现网页内容的误差. 各浏览器CSS解析: 1.大部分特殊字符IE浏览器支持,其他主流浏览器firefox,chrome,opera,safar ...

  3. maven本地仓库有jar包,maven install还是报错识别不到

    去本地仓库对应jar的目录下看下,有一个 _remote.repositories 的文件打开 ***.pom>xxx=***.jar>xxx= 这个 xxx 就是你maven的setti ...

  4. font-family:黑体;导致css定义全部不起作用

    css文件里font-family: "黑体";这句会导致后面的css定义全部不起作用了. 只要把font-family: "黑体"; 改成 font-fami ...

  5. [Vue CLI 3] 插件开发之 registerCommand 到底做了什么

    首先,我们看到在 package.json 中有 scripts 的定义: "scripts": { "serve": "vue-cli-servic ...

  6. yum源配置及详解

      红帽系列中,进行软件安装可以有三种方法,编译安装,rpm包安装,和yum源安装.其中yum方法安装最简单,因为它可以自动解决软件包之间的依赖关系... 一.常用yum源 yum源可以来源于多种文件 ...

  7. Mysql主从安装配置

    Mysql主从安装配置   环境: 主从服务器上的MySQL数据库版本同为5.1.34 主机IP:192.168.0.1 从机IP:192.168.0.2  一. MySQL主服务器配置 1.编辑配置 ...

  8. 【JZOJ4896】【NOIP2016提高A组集训第16场11.15】兔子

    题目描述 在一片草原上有N个兔子窝,每个窝里住着一只兔子,有M条路径连接这些窝.更特殊地是,至多只有一个兔子窝有3条或更多的路径与它相连,其它的兔子窝只有1条或2条路径与其相连.换句话讲,这些兔子窝之 ...

  9. Ceph 之Multisite 下的bucket reshard

    目录 一.背景和问题 二.bucket reshard 过程 主集群信息汇总 Multisite 下手动reshard References 一.背景和问题 默认情况下只有当单个bucket承载的ob ...

  10. “获取access_token”接口新增IP白名单保护