2019-10-30-C#-dotnet-core-局域网组播方法
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-局域网组播方法的更多相关文章
- dotnet core 获取 MacAddress 地址方法
本文告诉大家如何在 dotnet core 获取 Mac 地址 因为在 dotnetcore 是没有直接和硬件相关的,所以无法通过 WMI 的方法获取当前设备的 Mac 地址 但是在 dotnet c ...
- 【2019.10.30】SDN上机第1次作业
用字符命令搭建如下拓扑,要求写出命令 题目一: 字符命令如下: 题目二: 字符命令如下: 利用可视化工具搭建如下拓扑 要求支持OpenFlow 1.0 1.1 1.2 1.3,设置h1(10.0.0. ...
- 2019.10.30 csp-s模拟测试94 反思总结
头一次做图巨的模拟题OWO 自从上一次听图巨讲课然后骗了小礼物以后一直对图巨印象挺好的233 T1: 对于XY取对数=Y*log(x) 对于Y!取对数=log(1*2*3*...*Y)=log1+lo ...
- dotnet core 通过 frp 发布自己的网站
很多时候写出来的网站只能自己内网访问,本文告诉大家如何通过 Frp 将自己的 asp dotnet core 网站发布到外网,让小伙伴访问自己的网站 通过 frp 的方式,可以解决自己的服务器性能太差 ...
- asp dotnet core 支持客户端上传文件
本文告诉大家如何在 asp dotnet core 支持客户端上传文件 新建一个 asp dotnet core 程序,创建一个新的类,用于给客户端上传文件的信息 public class Kanaj ...
- Java单播、组播(多播)、广播的简单实现
简介 单播有TCP和UDP两种实现,组播(多播)和广播只有UDP一种实现.单播和广播基本一样,只是广播的数据包IP为广播IP. 单播 DatagramSocket和DatagramPacket 服 ...
- Alpha冲刺(7/10)——2019.4.30
所属课程 软件工程1916|W(福州大学) 作业要求 Alpha冲刺(7/10)--2019.4.30 团队名称 待就业六人组 1.团队信息 团队名称:待就业六人组 团队描述:同舟共济扬帆起,乘风破浪 ...
- ubuntu15.10 或者 16.04 或者 ElementryOS 下使用 Dotnet Core
这里我们不讲安装,缺少libicu52自行安装. 安装完成后使用dotnet restore或者build都会失败,一是报编译的dll不适合当前系统,二是编译到ubuntu16.04文件夹下会产生一些 ...
- 使用 dotnet core 和 Azure PaaS服务进行devOps开发(Web API 实例)
作者:陈希章 发表于 2017年12月19日 引子 这一篇文章将用一个完整的实例,给大家介绍如何基于dotnet core(微软.NET的最新版本,支持跨平台,跨设备的应用开发,详情请参考 https ...
随机推荐
- HR招聘_(三)_招聘方法论(招聘途径及流程)
1.招聘途径 网络招聘:企业官网,招聘网站,微信,论坛等. 校园招聘:学校信息栏海报,学校组织招聘会,校企业联合专场. 现场招聘会: 专场招聘会,人才市场招聘会. 猎头公司:猎头(年薪高于350K), ...
- CSS中各种居中方法
CSS中各种居中方法,本文回顾一下,便于后续的使用. 水平居中方法 1.行内元素居中 行内元素居中是只针对行内元素的,比如文本(text).图片(img).按钮等行内元素,可通过给父元素设置 text ...
- Direct2D 第1篇 最简单的D2D程序
原文:Direct2D 第1篇 最简单的D2D程序 编译之前,得先安装DirectX SDK #include <windows.h> #include <d2d1.h> #i ...
- 【水滴石穿】ReactNative-Redux-Thunk
老实说,运行出来的项目让人失望,毕竟我想看各种有趣的demo啊- 先放上源码地址:https://github.com/ludejun/ReactNative-Redux-Thunk 我们来一起看看代 ...
- golang中包的初始化
1.当一个go源程序被初始化时,首先去初始化所依赖的其他包,然后初始化该go源码文件的全局变量的初始化和执行初始化函数,其中该包所有的全局变量初始化在前,该包的初始化函数int在后.当所有包的初始化函 ...
- 【51NOD1304】字符串的相似度
题目描述 我们定义2个字符串的相似度等于两个串的相同前缀的长度.例如 "abc" 同 "abd" 的相似度为2,"aaa" 同 " ...
- day39-Spring 01-上次课内容回顾
- 【风马一族_php】PHP运算
运算 算术运算符 <?php //加法 $num1 = 10; $num2 = 43; echo $num1 + $num2; echo " "; var_dump($num ...
- 【JZOJ4854】【NOIP2016提高A组集训第6场11.3】小澳的坐标系
题目描述 小澳者表也,数学者景也,表动则景随矣. 小澳不喜欢数学,可数学却待小澳如初恋,小澳睡觉的时候也不放过. 小澳的梦境中出现了一个平面直角坐标系,自原点,向四方无限延伸. 小澳在坐标系的原点,他 ...
- Java练习 SDUT-2787_加密术
加密术 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 加密技术是一种常用的安全保密手段,利用加密技术可以把重要的数据变 ...