域名解析
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using UnityEngine;
public class Lesson2 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 知识点一 什么是域名解析?
//域名解析也叫域名指向、服务器设置、域名配置以及反向IP登记等等
//说得简单点就是将好记的域名解析成IP
//IP地址是网络上标识站点的数字地址,但是IP地址相对来说记忆困难
//所以为了方便记忆,采用域名来代替IP地址标识站点地址。
//比如 我们要登录一个网页 www.baidu.com 这个就是域名 我们可以通过记忆域名来记忆一个远端服务器的地址,而不是记录一个复杂的IP地址
//域名解析就是域名到IP地址的转换过程。域名的解析工作由DNS服务器完成
//我们在进行通信时有时会有需求通过域名获取IP
//所以这节课我们就来学习C#提供的域名解析相关的类
//域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务
//它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网
//是因特网上解决网上机器命名的一种系统,因为IP地址记忆不方便,就采用了域名系统来管理名字和IP的对应关系
#endregion
#region 知识点二 IPHostEntry类
//命名空间:System.Net
//类名:IPHostEntry
//主要作用:域名解析后的返回值 可以通过该对象获取IP地址、主机名等等信息
//该类不会自己声明,都是作为某些方法的返回值返回信息,我们主要通过该类对象获取返回的信息
//获取关联IP 成员变量:AddressList
//获取主机别名列表 成员变量:Aliases
//获取DNS名称 成员变量:HostName
#endregion
#region 知识点三 Dns类
//命名空间:System.Net
//类名:Dns
//主要作用:Dns是一个静态类,提供了很多静态方法,可以使用它来根据域名获取IP地址
//常用方法
//1.获取本地系统的主机名
print(Dns.GetHostName());
//2.获取指定域名的IP信息
//根据域名获取
//同步获取
//注意:由于获取远程主机信息是需要进行网路通信,所以可能会阻塞主线程
IPHostEntry entry = Dns.GetHostEntry("www.baidu.com");
for (int i = 0; i < entry.AddressList.Length; i++)
{
print("ip地址:" + entry.AddressList[i]);
}
for (int i = 0; i < entry.Aliases.Length; i++)
{
print("ip地址:" + entry.Aliases[i]);
}
print("DNS服务器名称:" + entry.HostName);
//异步获取
GetHostEntry();
#endregion
}
private async void GetHostEntry()
{
Task<IPHostEntry>task = Dns.GetHostEntryAsync("www.baidu.com");
await task;
for(int i=0;i<task.Result .AddressList .Length;i++)
{
print("ip地址:" + task.Result.AddressList[i]);
}
for(int i=0;i<task.Result .Aliases .Length;i++)
{
print("ip地址:" + task.Result.Aliases[i]);
}
print("DNS服务器名称:" + task.Result.HostName);
}
// Update is called once per frame
void Update()
{
}
}
异步方法async和await关键字
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
public class Lesson2 : MonoBehaviour
{
CancellationTokenSource source;
// Start is called before the first frame update
void Start()
{
#region 知识点一 什么是同步和异步
//同步和异步主要用于修饰方法
//同步方法:
//当一个方法被调用时,调用者需要等待该方法执行完毕后返回才能继续执行
//异步方法:
//当一个方法被调用时立即返回,并获取一个线程执行该方法内部的逻辑,调用者不用等待该方法执行完毕
//简单理解异步编程
//我们会把一些不需要立即得到结果且耗时的逻辑设置为异步执行,这样可以提高程序的运行效率
//避免由于复杂逻辑带来的的线程阻塞
#endregion
#region 知识点二 什么时候需要异步编程
//需要处理的逻辑会严重影响主线程执行的流畅性时
//我们需要使用异步编程
//比如:
//1.复杂逻辑计算时
//2.网络下载、网络通讯
//3.资源加载时
//等等
#endregion
#region 知识点三 异步方法async和await
//async和await一般需要配合Task进行使用
//async用于修饰函数、lambda表达式、匿名函数
//await用于在函数中和async配对使用,主要作用是等待某个逻辑结束
//此时逻辑会返回函数外部继续执行,直到等待的内容执行结束后,再继续执行异步函数内部逻辑
//在一个async异步函数中可以有多个await等待关键字
TestAsync();
print("主线程逻辑执行");
//使用async修饰异步方法
//1.在异步方法中使用await关键字(不使用编译器会给出警告但不报错),否则异步方法会以同步方式执行
//2.异步方法名称建议以Async结尾
//3.异步方法的返回值只能是void、Task、Task<>
//4.异步方法中不能声明使用ref或out关键字修饰的变量
//使用await等待异步内容执行完毕(一般和Task配合使用)
//遇到await关键字时
//1.异步方法将被挂起
//2.将控制权返回给调用者
//3.当await修饰内容异步执行结束后,继续通过调用者线程执行后面内容
//举例说明
//1.复杂逻辑计算(利用Task新开线程进行计算 计算完毕后再使用 比如复杂的寻路算法)
CalcPathAsync(this.gameObject, Vector3.zero);
//2.计时器
Timer();
print("主线程逻辑执行");
//3.资源加载(Addressables的资源异步加载是可以使用async和await的)
//注意:Unity中大部分异步方法是不支持异步关键字async和await的,我们只有使用协同程序进行使用
//虽然官方 不支持 但是 存在第三方的工具(插件)可以让Unity内部的一些异步加载的方法 支持 异步关键字
//https://github.com/svermeulen/Unity3dAsyncAwaitUtil
//虽然Unity中的各种异步加载对异步方法支持不太好
//但是当我们用到.Net 库中提供的一些API时,可以考虑使用异步方法
//1.Web访问:HttpClient
//2.文件使用:StreamReader、StreamWriter、JsonSerializer、XmlReader、XmlWriter等等
//3.图像处理:BitmapEncoder、BitmapDecoder
//一般.Net 提供的API中 方法名后面带有 Async的方法 都支持异步方法
#endregion
#region 总结
//异步编程async和await是一个比较重要的功能
//我们可以利用它配合Task进行异步编程
//虽然Unity自带的一些异步加载原本是不支持 异步方法关键字的
//但是可以利用别人写好的第三方工具 让他们支持 大家可以根据自己的需求选择性使用
#endregion
}
private async void TestAsync()
{
//1
print("进入异步方法");
//2
await Task.Run(() =>
{
Thread.Sleep(5000);
});
//3
print("异步方法后面的逻辑");
}
private async void CalcPathAsync(GameObject obj,Vector3 endPos)
{
print("开始处理寻路逻辑");
int value = 10;
await Task.Run(() =>
{
//复杂的寻路算法逻辑,通过休眠模拟算法的复杂性
Thread.Sleep(1000);
value = 50;
//是多线程,意味着我们不能在多线程里去访问Unity主线程场景里的对象
//这样写会报错
//print(obj.transform.position);
});
print("寻路计算完毕处理逻辑" + value);
obj.transform.position = Vector3.zero;
}
private async void Timer()
{
source = new CancellationTokenSource();
int i = 0;
while(!source.IsCancellationRequested)
{
print(i);
await Task.Delay(1000);
++i;
}
}
// Update is called once per frame
void Update()
{
if(Input .GetKeyDown (KeyCode.Space ))
{
source.Cancel();
}
}
}