Unity3D之TCP网络通信(客户端)

news/2024/9/8 19:11:17 标签: tcp/ip, unity

文章目录

    • 概述
      • TCP核心类
      • 异步机制
    • Unity中创建TCP客户端
    • Unity中其它脚本获取TCP客户端接受到的数据
    • 后续改进

本文将以Unity3D应用项目作为客户端去连接制定的服务器为例进行相关说明。
Unity官网参考资料: https://developer.unity.cn/projects/6572ea1bedbc2a001ef7df52

概述

在C#中,封装好了两个核心类,用于TCP网络编程:

TCP核心类

  • TcpListener
    用于创建一个监听器,监听客户端传入的TCP网络请求;作为服务器时使用。
  • TcpClient
    该类提供客户端连接,用于与服务器进行通信(用于发送和接收数据);作为客户端时使用。

异步机制

在Unity开发中,要注意所有与网络相关的操作都应该在协程或异步任务中执行,以避免阻塞UI线程。

C#中的异步操作使用async和await是配合使用的,async是修饰方法X的,await在被async修饰的方法里做标记,标记着一条语句y,主程序运行时候是逐方法逐语句的从上到下执行的,当主程序执行到被async修饰的X方法的时会进入该方法里一步一步的执行语句,当遇到被await标记的y语句的时分叉,主语句会跳出X方法,继续执行X方法下面的方法和语句。而y语句也是同时执行,当执行完了会继续向下执行y语句下面的语句直到X方法结束。参加下面的代码示例:

void Start()
{
      Dosomething();
}
public void Dosomething()
{
    X_Async();
    Debug.Log("正常的语句异步方法外的");
}
public async void X_Async()
{
    await y_等待3秒();     //这个方法会作用3秒时间
    Debug.Log("异步方法await后的语句");
}

// 上面输出的就是先输出"正常的语句异步方法外的"
// 过3秒在输出"异步方法await后的语句"。

异步操作的具体说明可参见C#异步编程

Unity中创建TCP客户端

首先,新建空模型(Create Empty),如重命名为ClientNode;
其次,创建一个新的脚本文件,如命名为Client.cs,并关联到ClientNode上;

TCP客户端的主要步骤如下:
a. 创建TcpClient实例;
b. 异步连接到服务器:tcpClient.ConnectAsync(ipaddr, port);
c. 异步接受数据:tcpClient.GetStream().ReadAsync(buffer, 0, buffer.Length);
d. 发送数据:tcpClient.GetStream().WriteAsync(data, 0, data.Length);

具体代码如下
Client.cs

using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using UnityEngine.Events;
using UnityEngine;

public class Client : MonoBehaviour
{
   TcpClient tcpClient;

   //接受到新的数据事件
   public UnityEvent RecvContentChanged;

   //接受的数据长度
   public int RecvLen { get; private set; } = 0;
   //接受的数据
   public string RecvContent { get; private set; } = string.Empty;

   public Client() { }

   public Client(TcpClient client)
   {
       tcpClient = client;
   }

   void Start()
   {
       TcpClient client = new TcpClient();
       //连接到本地服务器及连接端口8090(对应服务器的IP和端口)
       client.Connect("127.0.0.1", 8090);
   }

   void Update()
   {

   }

   //连接到指定IP服务器,以及相应的端口
   public async void Connect(string ipaddr, int port=8090)
   {
       try
       {
           //异步连接到指定服务器及端口
           await tcpClient.ConnectAsync(ipaddr, port);
           Debug.Log("连接成功...");
           //连接成功后接受服务器数据
           Receive();
       }
       catch (System.Exception e)
       {
           Debug.Log(e.Message);
       }
   }
   //接受数据
   public async void Receive()
   {
       try
       {
           while (tcpClient.Connected)
           {
               byte[] buffer = new byte[2048];
               //异步获取服务器数据
               int length = await tcpClient.GetStream().ReadAsync(buffer, 0, buffer.Length);
               if (length > 0)
               {
                   RecvLen = length;
                   RecvContent = Encoding.UTF8.GetString(buffer);

                   //发送新的数据以获取的事件
                   RecvContentChanged?.Invoke();

                   Debug.Log($"接收长度:{length}");
                   Debug.Log($"接收内容:{Encoding.UTF8.GetString(buffer)}");
               }
               else //如果获取的数据长度为0,则关闭连接
               {
                   tcpClient.Close();
               }
           }
       }
       catch (System.Exception e)
       {
           Debug.Log(e.Message);
           tcpClient.Close();
       }
   }
   //发送数据
   public async void Send(byte[] data)
   {
       try
       {
           //异步往服务器发送数据
           await tcpClient.GetStream().WriteAsync(data, 0, data.Length);
           Debug.Log("发送成功");
       }
       catch (System.Exception e)
       {
           Debug.Log(e.Message);
           tcpClient.Close();
       }
   }

}

Unity中其它脚本获取TCP客户端接受到的数据

在Client.cs的代码中,可以发现有如下的代码:

public UnityEvent RecvContentChanged;

该语句中引入了Unity.Event,它是对C#事件封装。通过绑定该事件,其它脚本文件可以来获取接受到的数据。

UnityEvent 对事件的操作提供了不一样的 API:

//绑定
public void AddListener(UnityAction call);
//调用
public void Invoke();
//解绑
public void RemoveListener(UnityAction call);

1. 如何使用
首先,我们在其他脚本(如MainLogic.cs)中创建一个函数:

    public void onRecvContentChanged()
   {
       string recvContent = client.RecvContent;
       Debug.Log($"Length:{client.RecvLen}, Context: {client.RecvContent}");
   }

两种方式进行绑定:
方法一 代码中绑定

//MainLogic.cs
public class MainLogic : MonoBehaviour
{
   public Client client;
   
    void Start()
   {
   	   client = new Client();
       client.RecvContentChanged.AddListener(onRecvContentChanged);
   }
   
   void Update()
   {
   }
   
   public void onRecvContentChanged()
   {
       string recvContent = client.RecvContent;
       Debug.Log($"Length:{client.RecvLen}, Context: {client.RecvContent}");
   }
}

方法二:Unity的Inspector中绑定

  1. 选择MainLogic关联的节点(如Train),将Client.cs关联到MainLogic中的Client变量在这里插入图片描述
  2. 选择ClientNode,新建(+)Recv Content Changed事件的响应,之后将Train节点拖到Inspector指定位置(如图),再依次绑定到MainLogic的onRecvContentChanged函数。
    在这里插入图片描述

后续改进

在客户端脚本Client.cs中,接受数据的时候限制了接受数据长度为2048,对于数据长度溢出的问题,后续再来改进优化。


http://www.niftyadmin.cn/n/5575574.html

相关文章

JavaDS —— 二叉搜索树、哈希表、Map 与 Set

前言 我们将学习 Map 与 Set 这两个接口下的 TreeMap 与 TreeSet ,HashMap 与 HashSet ,在学习这四个类使用之前,我们需要先学习 二叉搜索树与 哈希表的知识。 二叉搜索树 在学习二叉树的时候,我们就已经了解过二叉搜索树的概念…

WebKit的文本装饰艺术:CSS Text Decoration全解析

WebKit的文本装饰艺术:CSS Text Decoration全解析 CSS文本装饰(Text Decoration)是一组用于美化和增强网页文本表现的属性,它们可以为文本添加下划线、上划线、线删除和强调标记等效果。WebKit作为许多现代浏览器的渲染引擎&…

AI大模型学习必备十大网站

随着人工智能技术的快速发展,AI大模型(如GPT-3、BERT等)在自然语言处理、计算机视觉等领域取得了显著的成果。对于希望深入学习AI大模型的开发者和研究者来说,找到合适的学习资源至关重要。本文将为大家推荐十大必备网站&#xff…

盗梦空间续集(InceptionNeXt):使用Inception优化加速ConvNeXt实现ImageNet-1K的最佳精度

Abstract 灵感来自ViT的长距离建模能力,大核卷积最近被广泛研究和采用,以扩大感受野并提高模型性能,例如显著的工作ConvNeXt采用77深度卷积。虽然这种深度算子只消耗少量的FLOPs,但由于高内存访问成本,它在强大计算设…

sql-libs通关详解

1-4关 1.第一关 我们输入?id1 看回显,通过回显来判断是否存在注入,以及用什么方式进行注入,直接上图 可以根据结果指定是字符型且存在sql注入漏洞。因为该页面存在回显,所以我们可以使用联合查询。联合查询原理简单说一下&…

编写SpringBoot的自定义starter包

starter项目 先来看一下Starter的官方解释: Spring Boot Starter 是一种方便的依赖管理方式,它封装了特定功能或技术栈的所有必要依赖项和配置,使得开发者可以快速地将这些功能集成到Spring Boot项目中。Spring Boot官方提供了一系列的Star…

常见的NLP处理框架介绍!

自然语言处理(NLP)处理框架是指一系列用于开发、实现和部署自然语言处理应用程序的工具、库和框架。以下是一些主要的NLP处理框架的介绍: 一、NLTK(Natural Language Toolkit) 概述:NLTK是Python编程语言中…

【C++】—— 类和对象(一)

【C】—— 类和对象(一) 1、类的定义1.1、类定义1.1.1、类定义格式1.1.2、成员变量的标识1.1.3、C 中的 s t r u c t struct struct1.1.4、C 中的内联函数1.1.5、总结 1.2、访问限定符1.3、类域 2、实例化2.1、实例化的概念2.2、对象大小2.2.1、对象的大…