2019-11-1-asp-dotnet-core-简单开发P2P中央服务器
title | author | date | CreateTime | categories |
---|---|---|---|---|
asp dotnet core 简单开发P2P中央服务器
|
lindexi
|
2019-11-01 19:40:33 +0800
|
2019-11-01 19:10:28 +0800
|
dotnet
|
在做P2P的时候,如何让设备发现是整个开发里面最重要的部分。可以采用的方式有组播、扫描局域网、追踪服务器发现等方法。其中效率最高,发现效果最好的也就是使用中央服务器了。本文告诉大家如何使用 ASP.NET Core 写一个简单的 P2P 追踪服务器
在 P2P 里面的追踪服务器最重要的功能就是告诉设备,他周围有哪些设备,或告诉设备他需要的资源在哪些设备。这里只是告诉设备周围有哪些设备的就是本文需要开发的服务器,而告诉资源的就是 BT 服务器做的事情。两个方法对应不同的业务
只是告知周围设备的,适合用来局域网连接上。通过客户端访问,可以知道所在的外网 IP 地址,将记录的相同的外网 IP 地址的客户端返回就完成了。对比资源方式的优点在于,现在很多 BT 服务器都因为访问量太大而难以使用,原因是客户端每个资源都需要在服务器端注册,假设有1w个客户端,而每个客户端有100个资源,假设每10分钟需要注册一次。也就是每10分钟有100w次访问。当然这样的效果也就是很好的,面向外网有大量的客户端,能返回资源在哪个客户端可以提高资源寻找速度
本文的服务器也就是拿到客户端访问的 IP 然后返回记录的相同的外网 IP 地址的客户端
也就是在客户端访问的时候,需要客户端将自己的内网 IP 告诉服务器端,这样服务器端就将这个内网 IP 记下。下次在相同局域网有另一个客户端访问就可以返回记录的内网地址
当然,如果需要支持外网也没问题,只需要将记录的所有客户端选取活跃返回就可以
打开 VisualStudio 2019 新建一个 asp dotnet core 项目
因为涉及到数据库的存储,需要存放客户端的 IP 地址和活跃时间。所以需要装上相关的库。我的设备十分强,有32G的内存,所以我就使用内存作为数据库,通过安装下面库使用 EF 协助
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0" />
现在打开 Startup.cs 修改使用内存作为数据库
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); services.AddDbContext<NodeContext>(options =>
options.UseInMemoryDatabase("node"));
}
然后创建 NodeContext 作为存放客户端的信息的数据
public class NodeContext : DbContext
{
public NodeContext (DbContextOptions<NodeContext> options)
: base(options)
{
} public DbSet<KeahelnawwalyoNelwerchaje.Node> Node { get; set; }
} public class Node
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { set; get; } public string MainIp { set; get; } public string LocalIp { set; get; } public DateTime LastUpdate { set; get; }
}
对于客户端需要存的信息是客户端的外网 IP 地址,也就是 MainIp 属性,客户端的内网 IP 地址,也就是 LocalIp 属性,还有客户端活跃时间
客户端的访问通过 get 的方法,在参数传入客户端内网 IP 地址
[Route("api/[controller]")]
[ApiController]
public class PeerController : ControllerBase
{
public PeerController(NodeContext context)
{
_context = context;
} [HttpGet("{localIp}")]
public IActionResult GetPeer(string localIp)
{
// 忽略代码
} private readonly NodeContext _context;
在 GetPeer 方法可以通过asp dotnet core 获取用户真实 IP 地址 获取客户端的地址
从服务器找到相同的地址的客户端,更新当前客户端的时间,返回其他的客户端信息
[HttpGet("{localIp}")]
public IActionResult GetPeer(string localIp)
{
var ip = GetIp(); var nodeList = _context.Node.Where(temp => temp.MainIp == ip).ToList(); var node = nodeList.FirstOrDefault(temp => temp.LocalIp == localIp); if (node != null)
{
_context.Node.Remove(node);
nodeList.Remove(node);
} _context.Node.Add(new Node
{
MainIp = ip,
LocalIp = localIp,
LastUpdate = DateTime.Now
}); _context.SaveChanges();
return Ok(string.Join(';', nodeList.Select(temp => temp.LocalIp)));
}
当然,有一些客户端可能很久没有连接,这些需要判断如果过了一段时间没有活跃就从数据库移除客户端
var removeList = new List<Node>(); for (var i = 0; i < nodeList.Count; i++)
{
if (DateTime.Now - nodeList[i].LastUpdate > TimeSpan.FromHours(2))
{
removeList.Add(nodeList[i]);
nodeList.RemoveAt(i);
i--;
}
} _context.Node.RemoveRange(removeList);
修改后的代码
[HttpGet("{localIp}")]
public IActionResult GetPeer(string localIp)
{
var ip = GetIp(); var nodeList = _context.Node.Where(temp => temp.MainIp == ip).ToList(); var removeList = new List<Node>(); for (var i = 0; i < nodeList.Count; i++)
{
if (DateTime.Now - nodeList[i].LastUpdate > TimeSpan.FromHours(2))
{
removeList.Add(nodeList[i]);
nodeList.RemoveAt(i);
i--;
}
} var node = nodeList.FirstOrDefault(temp => temp.LocalIp == localIp); if (node != null)
{
_context.Node.Remove(node);
nodeList.Remove(node);
} _context.Node.Add(new Node
{
MainIp = ip,
LocalIp = localIp,
LastUpdate = DateTime.Now
});
_context.Node.RemoveRange(removeList); _context.SaveChanges();
return Ok(string.Join(';', nodeList.Select(temp => temp.LocalIp)));
}
本文代码放在 github 欢迎小伙伴访问
这样就完成了简单的追踪服务器,可以看到只需要很少的代码。客户端访问方法是通过 get 加上自己的内网地址,然后读取返回内容,用分号分开多个地址
为什么我不用 json 返回?原因是我的客户端都是很少的代码开发的,不想使用 json 库,有些客户端使用 c 写的,所以只能使用简单 get 方法,返回的也是字符串
有小伙伴问如果有一个外网地址就访问一次,那是不是数据库的内容就会占用。其实我不关注这个问题,因为我使用内存数据库,我大概几天就关机一次。另外,按照每个客户端报告一个内网 IP 加上端口,也就是大概21个字符,加上外网 IP 和 Id 这些属性,可以看到数据量是非常小。假设每个客户端需要 1kb 的内存,那么 1G 的内存足够 100w 客户端,如果有这么多客户端,我就可以去打广告。然而我只有 10 个客户端
本文的代码可以修改一下在你的项目中使用,非常简单,但是效果不错
客户端需要获取本机 IP 地址 加上本机的端口,拼接链接访问
var localIp = string.Join(';',
GetLocalIpList().Select(temp => $"{temp}:{port}"));
上面代码的 GetLocalIpList 方法请看我博客 dotnet 获取本机 IP 地址方法
然后拼接链接
var url = $"http://p2p.api.acmx.xyz/api/peer/{localIp}";
上面的链接就是我部署的链接,如果小伙伴不想自己写服务器,也可以用我的。如果我关机了,这个链接就访问不到
我的服务器虽然很好,但是网很差,所以我设置了超时时间比较长
var httpClient = new HttpClient()
{
Timeout = TimeSpan.FromMinutes(10)
}; using (httpClient)
{
var remoteIp = await httpClient.GetStringAsync(url);
var ipList = GetIpList(remoteIp).Where(temp =>
!string.IsNullOrEmpty(temp.ip) && !string.IsNullOrEmpty(temp.port)).ToList();
}
这里的 GetIpList 就是解析服务器返回
private IEnumerable<(string ip, string port)> GetIpList(string remoteIp)
{
var ipList = remoteIp.Split(';');
foreach (var ip in ipList)
{
yield return IpRegex.Parse(ip);
}
} class IpRegex
{
public static (string ip, string port) Parse(string str)
{
var regex = new Regex(@"(\d+\.\d+\.\d+\.\d+):(\d+)"); var match = regex.Match(str); if (match.Success)
{
var ip = match.Groups[1].Value;
var port = match.Groups[2].Value; return (ip, port);
} return default;
}
}
现在拿到了一些 IP 和端口,尝试访问这些客户端看能不能访问
2019-11-1-asp-dotnet-core-简单开发P2P中央服务器的更多相关文章
- asp dotnet core 通过图片统计 csdn 用户访问
在 csdn 的访问统计里面,只能用 csdn 提供的访问统计,因为在 csdn 中不支持在博客加上 js 代码,也就是无法使用友盟等工具统计. 通过在 asp dotnet core 创建一个图片链 ...
- win10 uwp 手把手教你使用 asp dotnet core 做 cs 程序
本文是一个非常简单的博客,让大家知道如何使用 asp dot net core 做后台,使用 UWP 或 WPF 等做前台. 本文因为没有什么业务,也不想做管理系统,所以看到起来是很简单. Visua ...
- 《ASP.NET Core应用开发入门教程》与《ASP.NET Core 应用开发项目实战》正式出版
“全书之写印,实系初稿.有时公私琐务猬集,每写一句,三搁其笔:有时兴会淋漓,走笔疾书,絮絮不休:有时意趣萧索,执笔木坐,草草而止.每写一段,自助覆阅,辄摇其首,觉有大不妥者,即贴补重书,故剪刀浆糊乃不 ...
- 《ASP.NET Core项目开发实战入门》带你走进ASP.NET Core开发
<ASP.NET Core项目开发实战入门>从基础到实际项目开发部署带你走进ASP.NET Core开发. ASP.NET Core项目开发实战入门是基于ASP.NET Core 3.1 ...
- ASP.NET Core Web开发学习笔记-1介绍篇
ASP.NET Core Web开发学习笔记-1介绍篇 给大家说声报歉,从2012年个人情感破裂的那一天,本人的51CTO,CnBlogs,Csdn,QQ,Weboo就再也没有更新过.踏实的生活(曾辞 ...
- ASP.NET Core 企业级开发架构简介及框架汇总
企业开发框架包括垂直方向架构和水平方向架构.垂直方向架构是指一个应用程序的由下到上叠加多层的架构,同时这样的程序又叫整体式程序.水平方向架构是指将大应用分成若干小的应用实现系统功能的架构,同时这样的系 ...
- 使用Asp.Net Core MVC 开发项目实践[第一篇:项目结构说明]
先从下图看整体项目结构: Mango.Manager: 为后台管理项目 Mango.Web: 为前台项目 Mango.Framework.Core: 为常用的基础操作类项目 Mango.Framewo ...
- ASP.NET Core 企业级开发架构简介及框架汇总 (转载)
ASP.NET Core 企业开发架构概述 企业开发框架包括垂直方向架构和水平方向架构.垂直方向架构是指一个应用程序的由下到上叠加多层的架构,同时这样的程序又叫整体式程序.水平方向架构是指将大应用分成 ...
- win10 uwp 使用 asp dotnet core 做图床服务器客户端
原文 win10 uwp 使用 asp dotnet core 做图床服务器客户端 本文告诉大家如何在 UWP 做客户端和 asp dotnet core 做服务器端来做一个图床工具 服务器端 从 ...
随机推荐
- GULP入门之API(二)
GULP的API gulp.src(globs[, options]) 输出(Emits)符合所提供的匹配模式(glob)或者匹配模式的数组(array of globs)的文件. 将返回一个 Vin ...
- 架构hive2mysql流程
1.分析参数 args = new String[5]; args[0]="d:/3-20.sql"; args[1]="-date"; args[2]=&qu ...
- day18 8.jdbc中设置事务隔离级别
设置数据库事务隔离级别特殊需求才有,后面很少用.因为数据库本身是事务隔离级别的,mysql的事务隔离级别是Repeatable read,可以解决脏读和不可重复读.不用设置,人家数据库是有事务隔离级别 ...
- Leetcode401Binary Watch二进制手表
二进制手表顶部有 4 个 LED 代表小时(0-11),底部的 6 个 LED 代表分钟(0-59). 每个 LED 代表一个 0 或 1,最低位在右侧. 给定一个非负整数 n 代表当前 LED 亮着 ...
- 字符串常用方法(转载--https://www.cnblogs.com/ABook/p/5527341.html)
一.String类String类在java.lang包中,java使用String类创建一个字符串变量,字符串变量属于对象.java把String类声明的final类,不能有类.String类对象创建 ...
- Spring相关技术记录
@ResponseStatus(value=) Hibernate OneToOne: 使用optional=false,才能使用lazy 如果关联字段是当前表的主键,我试了不加optional=fa ...
- 读书笔记--Spring in Action 目录
1.Spring之旅 1.1 简化java 开发 1.1.1 激发pojo 的潜能 1.1.2 依赖注入1.1.3 应用切面1.1.4 使用模板消除样板式代码1.2 容纳你的bean1.2.1 与应用 ...
- day 53
目录 orm表关系如何建立 django中间件 路由层 反向解析 路由分发 名称空间 伪静态 虚拟环境 django版本的区别 视图层 orm表关系如何建立 多对多 一对多 一对一 换 ...
- python实例 文件处理
对比Java,python的文本处理再次让人感动 #! /usr/bin/python spath="D:/download/baa.txt" f=open(spath," ...
- 【CodeVS】1083 Cantor表
1083 Cantor表 1999年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 现代数学的著名证明之 ...