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. wamp httpd-vhosts.conf

    配置Apache的httpd.conf文件 Include conf/extra/httpd-vhosts.conf 修改apache的vhost文件 <VirtualHost *:> D ...

  2. vue使用填坑之:model和v-model的区别

    v-model通常用于input的双向数据绑定 <input v-model="parentMsg">,也可以实现子组件到父组件数据的双向数据绑定:首先说说v-mode ...

  3. CentOS7安装步骤

    CentOS7安装详解   本文基于vmware workstations进行CentOS7安装过程展示,关于vmware workstations安装配置本人这里不再介绍,基本过程相当于window ...

  4. Openck_Swift源代码分析——添加、删除设备时算法详细的实现过程

    1 初始加入设备后.上传Object的详细流程  前几篇博客中,我们讲到环的基本原理即详细的实现过程,加入我们在初始创建Ring是执行例如以下几条命令: •swift-ring-builder obj ...

  5. 获得CSM(Certified Scrum Master)-价值驱动交付。

    2019年越来越多的企业开始实行敏捷转型,紧随时代潮流,学习最先进的科学管理方法,找到正确的人(团队),为企业交付高价值的产品服务. 导师Ethan ,培训的课程让人收益匪浅,活到老学到老,丰富的知识 ...

  6. day38 12-Spring的Bean的属性的注入:名称空间p

    xmlns="http://www.springframework.org/schema/beans"是默认的名称空间. xmlns:xsi="http://www.w3 ...

  7. 记一次goland的包导入问题

    昨天把go的GOPATH环境变量设置成了“/home/mi/app/gopath”,今天用goland新建的项目在/home/mi/go/src目录下,名字是studygolang,如下图. 结果导入 ...

  8. Wireshark抓包常见问题解析(转)

    1. tcp out-of-order(tcp有问题) 解答: 1). 应该有很多原因.但是多半是网络拥塞,导致顺序包抵达时间不同,延时太长,或者包丢失,需要重新组合数据单元 因为他们可能是通过不同的 ...

  9. Jmeter VS LR参数取值方式和迭代方式

    Jmeter的参数化 Jmeter中的参数就是变量. 变量的来源:测试计划.UDV.CSV.函数.正则表达式.数据库. 以Jmeter的CSV文件参数化为例:

  10. MySQL非安装版安装

    1 数据库的打开方式(非安装版本) 1.解压mysql-5.7.12-winx64.zip到一个路径上没有空格没有汉字的目录中 2.复制my-default.ini重命名为my.ini 3.命令行进入 ...