2025-03-21 Unity 网络基础3——TCP网络通信准备知识

news2025/3/27 6:04:33

文章目录

  • 1 IP/端口类
    • 1.1 IPAddress
    • 1.2 IPEndPoint
  • 2 域名解析
    • 2.1 IPHostEntry
    • 2.2 Dns
  • 3 序列化与反序列化
    • 3.1 序列化
      • 3.1.1 内置类型 -> 字节数组
      • 3.1.2 字符串 -> 字节数组
      • 3.1.3 类对象 -> 字节数组
    • 3.2 反序列化
      • 3.2.1 字节数组 -> 内置类型
      • 3.2.2 字节数组 -> 字符串
      • 3.2.3 字节数组 -> 类对象

1 IP/端口类

​ 要进行网络通信,首先需要找到对应设备,IP和端口号是定位网络中设备必不可少的关键元素。

​ C# 中提供了对应的 IP 和端口相关的类来声明对应信息。

1.1 IPAddress

  • 命名空间:System.Net
  • 类名:IPAddress
// 1.用 byte 数组进行初始化
byte[] ipAddress = new byte[] { 118, 102, 111, 11 };
IPAddress ip1 = new IPAddress(ipAddress);

// 2.用 long 长整型进行初始化
//   4 字节对应的长整型,一般不建议使用
//   76, 66, 6F, 0B 对应 10 进制下的 118, 102, 111, 11
IPAddress ip2 = new IPAddress(0x76666F0B);

// 3.推荐使用的方式,使用字符串转换
IPAddress ip3 = IPAddress.Parse("118.102.111.11");

​ **特殊 IP 地址:**127.0.0.1 代表本机地址。

1.2 IPEndPoint

​ IPEndPoint 类将网络端点表示为 IP 地址和端口号,是 IP 地址和端口号的组合。

  • 命名空间:System.Net
  • 类名:IPEndPoint
// 1.用 4 子节长整型 ip 与端口号初始化
IPEndPoint ipPoint = new IPEndPoint(0x79666F0B, 8080);

// 2.用 IPAddress 与端口号初始化,推荐使用
IPEndPoint ipPoint2 = new IPEndPoint(IPAddress.Parse("118.102.111.11"), 8080);

2 域名解析

​ IP 地址记忆困难,为了方便记忆,采用域名来代替 IP 地址标识站点地址。比如登录百度网页时,通过域名 “www.baidu.com”进行登录,而不是记录复杂的 IP 地址。

​ 域名解析即域名到 IP 地址的转换过程,也称域名指向、服务器设置、域名配置以及反向 IP 登记等。域名解析工作由 DNS(Domain Name System)服务器完成。

​ 域名系统(Domain Name System,DNS)是互联网的一项服务,是将域名和 IP 地址相互映射的分布式数据库,能够更方便地访问互联网。

2.1 IPHostEntry

​ 该类不会主动声明,而是作为某些方法的返回值返回信息。

​ 主要通过该类对象获取返回的信息。

  • 命名空间:System.Net
  • 类名:IPHostEntry
  • 主要作用:域名解析后的返回值 可以通过该对象获取 IP 地址、主机名等信息。
namespace System.Net
{
  public class IPHostEntry
  {
    public IPAddress[] AddressList { get; set; } // 关联 IP

    public string[] Aliases { get; set; }  // 主机别名列表

    public string HostName { get; set; } // DNS 名称
  }
}

2.2 Dns

​ 主要作用:提供静态方法,根据域名获取 IP 地址。

  • 命名空间:System.Net
  • 类名:Dns

同步加载

using System.Net;

public class Lesson2 : MonoBehaviour
{
    private void Start()
    {
        // 1.获取本地系统的主机名
        print(Dns.GetHostName());

        // 2.同步获取指定 IP 地址的 DNS 信息
        var entry = Dns.GetHostEntry("www.baidu.com"); // 网页端口号默认为 80
        foreach (var ip in entry.AddressList)
        {
            print("ip: " + ip);
        }

        foreach (var alias in entry.Aliases)
        {
            print("alias: " + alias);
        }

        print("DNS 服务器名称: " + entry.HostName);
    }
}
image-20250319115815011

异步加载

using System.Net;

public class Lesson2 : MonoBehaviour
{
    private void Start()
    {
        // 1.获取本地系统的主机名
        print(Dns.GetHostName());

        // 2.异步获取指定 IP 地址的 DNS 信息
        GetHostEntryAsync();
    }

    private async void GetHostEntryAsync()
    {
        var entry = await Dns.GetHostEntryAsync("www.baidu.com");
        foreach (var ip in entry.AddressList)
        {
            print("ip: " + ip);
        }

        foreach (var alias in entry.Aliases)
        {
            print("alias: " + alias);
        }

        print("DNS 服务器名称: " + entry.HostName);
    }
}

3 序列化与反序列化

​ 在网络通信中,需要将传递的类对象信息序列化为 2 进制数据(商业游戏中,一般为 byte 字节数组),再将该 2 进制数据通过网络传输给远端设备,远端设备获取到该 2 进制数据后再将其反序列化为对应的类对象。

image-20250319120257101
  • 序列化:将类对象信息转换为可保存或传输的格式的过程。

  • 反序列化:与序列化相反,将保存或传输过来的格式转换为类对象的过程。

网络通信中常用内容:

  1. BitConverter:主要用于处理各类型和字节数组间的相互转换。
  2. Encoding:主要用于处理字符串类型和字节数组间的相互转换。
  3. File:文件操作类,用于操作文件。
  4. FileStream:文件流类,以流的形式进行文件存储读取操作。
  5. MemoryStrem:内存流对象。
  6. 加密:了解 2 进制数据加密的常用手段和思路。

​ BinaryFormatter 类可以将 C# 类对象快速转换为字节数组数据。

​ 在网络开发时,不会使用 BinaryFormatter 进行数据序列化和反序列化。因为客户端和服务端的开发语言多数情况下不同,BinaryFormatter 序列化的数据无法兼容其它语言。

​ 若保证开发语言均为 C#,可以使用 BinaryFormatter,参考链接:2023-05-27 Unity 2进制4——类对象的序列化与反序列化_unity 二进制序列化-CSDN博客。

3.1 序列化

3.1.1 内置类型 -> 字节数组

  • 关键类:BitConverter
  • 所在命名空间:System
  • 主要作用:除字符串的其它常用类型和字节数组相互转换。
using System;
using System.Text;

public class Lesson3 : MonoBehaviour
{
    private void Start()
    {
        var bytes = BitConverter.GetBytes(1); // 将 1 转为 byte 数组
    }
}

3.1.2 字符串 -> 字节数组

  • 关键类:Encoding
  • 命名空间:System.Text
  • 主要作用:将字符串类型和字节数组相互转换,并且决定转换时使用的字符编码类型。网络通信时建议使用 UTF-8 类型。
using System;
using System.Text;

public class Lesson3 : MonoBehaviour
{
    private void Start()
    {
        var bytes2 = Encoding.UTF8.GetBytes("hello world"); // 将 "hello world" 转为 byte 数组
    }
}

3.1.3 类对象 -> 字节数组

​ 以如下自定义类为例:

public class PlayerInfo
{
    public int    Lev;
    public string Name;
    public int    Exp;
    public bool   Sex;
}
  1. 明确字节数组的容量

    对于 string 类型,除了存储字符串内容,还需要先存储其长度。

    否则,反序列化时无法确定后续成员的索引位置。

    var bytesLength = sizeof(int) +                         // Lev:int 类型,占用 4 个字节
                      sizeof(int) +                         // Name Length:int 类型,占用 4 个字节
                      Encoding.UTF8.GetBytes(Name).Length + // Name:string 类型,占用 Name.Length 个字节
                      sizeof(int) +                         // Exp:int 类型,占用 4 个字节
                      sizeof(bool);                         // Sex:bool 类型,占用 1 个字节
    
  2. 申明装载信息的字节数组容器

    var playerBytes = new byte[bytesLength];
    
  3. 将对象信息转为字节数组,放入该容器中

    CopyTo 方法的第二个参数代表从容器的第几个位置开始存储。

    var offset = 0;
    
    // Lev
    BitConverter.GetBytes(Lev).CopyTo(playerBytes, offset);
    offset += sizeof(int);
    
    // Name
    var strBytes = Encoding.UTF8.GetBytes(Name);
    BitConverter.GetBytes(strBytes.Length).CopyTo(playerBytes, offset); // 存储长度
    offset += sizeof(int);
    strBytes.CopyTo(playerBytes, offset); // 存储内容
    offset += strBytes.Length;
    
    // Exp
    BitConverter.GetBytes(Exp).CopyTo(playerBytes, offset);
    offset += sizeof(int);
    
    // Sex
    BitConverter.GetBytes(Sex).CopyTo(playerBytes, offset);
    offset += sizeof(bool);
    

​ 完整代码:

public class PlayerInfo
{
    public int    Lev;
    public string Name;
    public int    Exp;
    public bool   Sex;

    public byte[] GetBytes()
    {
        var bytesLength = sizeof(int) +                         // Lev:int 类型,占用 4 个字节
                          sizeof(int) +                         // Name Length:int 类型,占用 4 个字节
                          Encoding.UTF8.GetBytes(Name).Length + // Name:string 类型,占用 Name.Length 个字节
                          sizeof(int) +                         // Exp:int 类型,占用 4 个字节
                          sizeof(bool);                         // Sex:bool 类型,占用 1 个字节

        var playerBytes = new byte[bytesLength];

        var offset = 0;

        // Lev
        BitConverter.GetBytes(Lev).CopyTo(playerBytes, offset);
        offset += sizeof(int);

        // Name
        var strBytes = Encoding.UTF8.GetBytes(Name);
        BitConverter.GetBytes(strBytes.Length).CopyTo(playerBytes, offset); // 存储长度
        offset += sizeof(int);
        strBytes.CopyTo(playerBytes, offset); // 存储内容
        offset += strBytes.Length;

        // Exp
        BitConverter.GetBytes(Exp).CopyTo(playerBytes, offset);
        offset += sizeof(int);

        // Sex
        BitConverter.GetBytes(Sex).CopyTo(playerBytes, offset);
        offset += sizeof(bool);

        return playerBytes;
    }
}

3.2 反序列化

3.2.1 字节数组 -> 内置类型

  • 关键类:BitConverter
  • 所在命名空间:System
  • 主要作用:除字符串的其它常用类型和字节数组相互转换。
byte[] bytes = BitConverter.GetBytes(99);
int i = BitConverter.ToInt32(bytes, 0);
print(i); // 99

3.2.2 字节数组 -> 字符串

  • 关键类:Encoding
  • 命名空间:System.Text
  • 主要作用:将字符串类型和字节数组相互转换,并且决定转换时使用的字符编码类型。网络通信时建议使用 UTF-8 类型。
byte[] bytes2 = Encoding.UTF8.GetBytes("hello world!");
string str = Encoding.UTF8.GetString(bytes2, 0, bytes2.Length);
print(str); // hello world!

3.2.3 字节数组 -> 类对象

  1. 获取到对应的字节数组

    PlayerInfo info = new PlayerInfo
    {
        Lev  = 10,
        Name = "zheliku",
        Exp  = 88,
        Sex  = false
    };
    
    byte[] playerBytes = info.GetBytes();
    
  2. 将字节数组按照序列化时的顺序进行反序列化

    将对应字节分组转换为对应类型变量。

    PlayerInfo info2 = new PlayerInfo();
    
    // 等级
    int index = 0;
    info2.Lev =  BitConverter.ToInt32(playerBytes, index);
    index     += 4;
    print(info2.Lev); // 10
    
    // 姓名的长度
    int length = BitConverter.ToInt32(playerBytes, index);
    index += 4;
    
    // 姓名字符串
    info2.Name =  Encoding.UTF8.GetString(playerBytes, index, length);
    index      += length;
    print(info2.Name); // zheliku
    
    // 攻击力
    info2.Exp =  BitConverter.ToInt16(playerBytes, index);
    index     += 2;
    print(info2.Exp); // 88
    
    // 性别
    info2.Sex =  BitConverter.ToBoolean(playerBytes, index);
    index     += 1;
    print(info2.Sex); // false
    

​ 完整代码:

public class PlayerInfo
{
    public int    Lev;
    public string Name;
    public int    Exp;
    public bool   Sex;

    public byte[] GetBytes()
    {
        ...
    }
    
    public void FromBytes(byte[] bytes)
    {
        // 等级
        int index = 0;
        Lev   =  BitConverter.ToInt32(bytes, index);
        index += 4;

        // 姓名的长度
        int length = BitConverter.ToInt32(bytes, index);
        index += 4;

        // 姓名字符串
        Name  =  Encoding.UTF8.GetString(bytes, index, length);
        index += length;

        // 攻击力
        Exp   =  BitConverter.ToInt16(bytes, index);
        index += 2;

        // 性别
        Sex   =  BitConverter.ToBoolean(bytes, index);
        index += 1;
    }
}

​ 更多序列化进阶内容,参考文章:2025-03-21 Unity 序列化 —— 自定义2进制序列化-CSDN博客。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2321387.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

静态时序分析:SDC约束命令set_min_pulse_width详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 最小脉冲宽度检查用于确保一个单元的时钟引脚和异步置位/复位引脚的的脉冲宽度满足最小要求,如果违反该要求,则可能出现功能错误。严格意…

推荐1款简洁、小巧的实用收音机软件,支持手机和电脑

聊一聊 没想到现在还有人喜欢听广播。 我一直以为听广播必须要用那种小广播机才可以。 原来手机或电脑上也是可以的。 今天给大家分享一款可以在电脑和手机上听广播的软件。 软件介绍 龙卷风收音机 电台广播收音机分电脑和手机两个版本。 电脑端无需安装,下载…

HO与OH差异之Navigation

在上一篇的内容中我们进一步的了解了Navigation的用法,但是既然写到这里了我就再来扩充一下有关Navigation的内容。 HarmonyOS与OpenHarmony之间有些写法与内容是有差异的,就比如Navigation的跳转。以下内容中HarmonyOS我都简称为HO,OpenHar…

模糊规则激活方法详解(python实例对比)

前文我们已经了解了多种隶属函数,如三角形、梯形、高斯型、S型和Z型,并且讨论了模糊推理的基本过程,包括模糊化、规则评估、聚合和解模糊化。我们还了解了如何生成模糊规则的方法,比如专家经验、聚类分析、决策树、遗传算法和ANFI…

Web前端考核 JavaScript知识点详解

一、JavaScript 基础语法 1.1 变量声明 关键字作用域提升重复声明暂时性死区var函数级✅✅❌let块级❌❌✅const块级❌❌✅ 1.1.1变量提升的例子 在 JavaScript 中,var 声明的变量会存在变量提升的现象,而 let 和 const 则不会。变量提升是指变量的声…

Spring Boot3 配置文件

统一配置文件管理 SpringBoot工程下,进行统一的配置管理,你想设置的任何参数(端口号、项目根路径、数据库连接信息等等)都集中到一个固定位置和命名的配置文件(application.properties或application.yml)中&#xff0…

消防设施操作员考试:巧用时间高效备考攻略

合理规划时间是备考消防设施操作员考试的关键,能让学习事半功倍。​ 一、制定详细时间表​ 根据备考时间和考试内容,制定每日、每周的学习计划。将学习时间合理分配给理论知识学习、技能实操练习和模拟考试。例如,每天安排 3 - 4 小时学习理…

深度学习技术与应用的未来展望:从基础理论到实际实现

深度学习作为人工智能领域的核心技术之一,近年来引起了极大的关注。它不仅在学术界带来了革命性的进展,也在工业界展现出了广泛的应用前景。从图像识别到自然语言处理,再到强化学习和生成对抗网络(GAN),深度…

FastStoneCapture下载安装教程(附安装包)专业截图工具

文章目录 前言FastStoneCapture下载FastStoneCapture安装步骤FastStoneCapture使用步骤 前言 在日常工作与学习里,高效截图工具至关重要。本教程将为你呈现FastStoneCapture下载安装教程,助你轻松拥有。 FastStoneCapture下载 FastStone Capture 是一款…

26考研——图_图的遍历(6)

408答疑 文章目录 三、图的遍历图的遍历概述图的遍历算法的重要性图的遍历与树的遍历的区别图的遍历过程中的注意事项避免重复访问遍历算法的分类遍历结果的不唯一性 广度优先搜索广度优先搜索(BFS)概述BFS 的特点广度优先遍历的过程示例图遍历过程 BFS …

C++类与对象的第一个简单的实战练习-3.24笔记

在哔哩哔哩学习的这个老师的C面向对象高级语言程序设计教程&#xff08;118集全&#xff09;讲的真的很不错 实战一&#xff1a; 情况一&#xff1a;将所有代码写到一个文件main.cpp中 #include<iostream> //不知道包含strcpy的头文件名称是什么,问ai可知 #include<…

4.1 C#获取目录的3个方法的区别

C#中常用有如下3个获取目录的方式如下 1.Directory.GetCurrentDirectory():获取当前工作目录&#xff0c;工作目录可能被用户或其他代码修改。尽量少用。&#xff08;似乎只要在运行中使用另存为或者打开某个文件夹&#xff0c;当前工作目录就修改&#xff09; 2.Application…

oracle数据库(数据库启动关闭/sqlplus登录及基本操作/设置字符集/distinct去重)

目录 1. Oracle数据库启动 2. Oracle数据库关闭 3. sqlplus登录Oracle数据库 3.1 使用sqlplus登录Oracle数据库 3.2 使用sqlplus登录Oracle数据库 3.3 远程登录 3.4 解锁用户 3.5 修改用户密码 3.6 查看当前语言环境 4. sqlplus基本操作 4.1 显示当前用户 4.2 查看当前用户…

1、SpringBoot集成MyBatis

&#xff08;1&#xff09;创建SpringBoot项目 &#xff08;2&#xff09;集成MyBatis 导入坐标 <!-- 连接数据库&#xff0c;版本5 --> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><versi…

Linux实操篇-权限管理

目录 传送门前言一、权限管理概念二、权限管理实战1. Linux文件权限模型1.1 文件的三种基本权限1.2 权限的三类主体 2. 查看文件权限3. 修改文件权限3.1 使用符号方式修改权限3.2 使用数字方式修改权限 4. 特殊权限4.1 SUID&#xff08;Set User ID&#xff09;4.2 SGID&#x…

阿里开源的免费数据集成工具——DataX

企业里真实的数据流转是什么样子的呢&#xff1f; 左侧描述了一个企业真实的样子&#xff0c;我们总是需要把数据从一个地方搬到另一个地方&#xff0c;最后就是搬来搬去搬成了一张张解不开的网。 右侧则表达了使用DataX为中心实现数据的同步。 什么是DataX DataX是一个异构…

【前端】使用 HTML、CSS 和 JavaScript 创建一个数字时钟和搜索功能的网页

文章目录 ⭐前言⭐一、项目结构⭐二、HTML 结构⭐三、CSS 样式⭐四、JavaScript 功能⭐五、运行效果⭐总结 标题详情作者JosieBook头衔CSDN博客专家资格、阿里云社区专家博主、软件设计工程师博客内容开源、框架、软件工程、全栈&#xff08;,NET/Java/Python/C&#xff09;、数…

地理信息可视化技术大全【WebGIS 教程一】

前言&#xff1a; 在当今数据驱动的时代&#xff0c;地理信息技术&#xff08;GIS&#xff09;和空间数据可视化已成为科学研究、商业决策和智慧城市建设的重要工具。随着Web技术的快速发展&#xff0c;基于浏览器端的地图渲染和地理信息处理能力显著增强&#xff0c;各类开源与…

SLAM十四讲【四】相机与图像

SLAM十四讲【四】相机与图像 SLAM十四讲【一】基本概念 SLAM十四讲【二】三维空间刚体运动 SLAM十四讲【三】李群与李代数 SLAM十四讲【四】相机与图像 SLAM十四讲【五】线性优化 SLAM十四讲【六】视觉里程计 SLAM十四讲【七】回环检测 SLAM十四讲【八】建图 文章目录 SLAM十四…

类和对象-运算符重载-C++

1.加号运算符重载 1.成员函数重载调用 函数的定义部分&#xff08;这里的person是返回值类型&#xff0c;不是说构造函数&#xff09; class person { public:person operator(person& p){person temp;temp.a this->a p.a;temp.b this->b p.b;return temp;}in…