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 ...
随机推荐
- 数组的方法之(Array.prototype.filter() 方法)
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素. 注意: filter() 不会对空数组进行检测. 注意: filter() 不会改变原始 ...
- GitHub的注册与使用
1. 注册账号: 地址: https://github.com/输入账号.邮箱.密码,然后点击注册按钮. 2. 初始设置 注册完成后,选择Free免费账号完成设置 3.验证账号 新建一个仓库 发现邮箱 ...
- Django 自定义auth_user
1 导入AbstractUser from django.contrib.auth.models import AbstractUser 1 2 创建类UserProfile并继承AbstractUs ...
- OpenCV灰度化图像
OpenCV2版本号非常多函数发生了变化.比如二值化,其演示样例: void CmyMFC2Dlg::OnBnClickedButton1() { // TODO: Add your control ...
- 客户端connect返回错误显示No route to host
务器程序运行起来后,客户端connect返回错误显示No route to host,但是两台机子能ping通 是firewall的问题, services iptables stop应该就ok了
- 使用Fiddler抓取到的“姐夫酷”API接口
下午本来准备抓取些网页视频地址,做一个小的视频app,用来学习ijkplayer,无意中发现了一个app--姐夫酷,这是一个很简单的网页,它也有相应的一个比较简单的android app. 于是心血来 ...
- 洛谷 P2146 [NOI2015]软件包管理器 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 输出样例#1: 输入样例#2: 输出样例#2: 说明 说明 思路 AC代码 总结 题面 题目链接 P ...
- python系列之(5)PyMySQL的使用
简介 PyMySQL是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中是使用mysqldb. 安装 pip3 install pymysql 创建连接 #!/usr ...
- IDEA入门(1)--lombok和Junit generator2插件的运用
前言 最近在慕课网看到了一些视频,准备从0开始做一个电商网站.视频中的大牛用的java的IDE都是IDEA,让我很纠结.从as到MyEclipse,好不容易稍微熟悉了一下MyEclipse的基本操作, ...
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...