Unity中的简易TCP服务器/客户端
在本文中,我将向你介绍一个在Unity中实现的简单TCP服务器脚本,和一个简单的客户端脚本.
脚本 MyTcpServer
允许Unity应用创建一个TCP服务器,监听客户端的连接、异步处理客户端消息,并通过事件与Unity应用中的其他模块进行通信。
MyTcpServer
类是使用 C# 的 TcpListener
实现的自定义 TCP 服务器,该服务器监听指定端口的传入 TCP 连接,并以异步、非阻塞的方式处理与客户端的通信.
AcceptClientsAsync
方法是一个异步方法,使用 TcpListener.AcceptTcpClientAsync()
来接受客户端的连接。每当一个新客户端连接时,服务器会将其添加到 connectedClients
列表中,并为该客户端创建一个新的任务 (Task.Run()
) 来处理客户端的消息。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using System.IO;
using System.Collections.Generic;public class MyTcpServer
{private static MyTcpServer instance;private TcpListener tcpListener;private CancellationTokenSource cts = new CancellationTokenSource();private List<TcpClient> connectedClients = new List<TcpClient>(); // 管理客户端连接public static bool isOnce = false;public static event Action<string> sendEvent;public static MyTcpServer Instance{get{if (instance == null){instance = new MyTcpServer();}return instance;}}public void StartServer(){try{var p = Path.Combine(Application.streamingAssetsPath, "MyPort.txt");if (!File.Exists(p)) return;var port = File.ReadAllText(p, Encoding.UTF8);Debug.Log($"Starting server on port {port}");tcpListener = new TcpListener(IPAddress.Any, int.Parse(port));tcpListener.Start();isOnce = true;Task.Run(() => AcceptClientsAsync(cts.Token));}catch (Exception ex){Debug.LogError($"Error starting server: {ex.Message}");}}private async Task AcceptClientsAsync(CancellationToken token){while (!token.IsCancellationRequested){try{TcpClient client = await tcpListener.AcceptTcpClientAsync();Debug.Log($"Client connected: {client.Client.RemoteEndPoint}");connectedClients.Add(client);_ = Task.Run(() => HandleClientAsync(client, token));}catch (Exception ex){Debug.LogError($"Error accepting client: {ex.Message}");}}}private async Task HandleClientAsync(TcpClient client, CancellationToken token){using (client){NetworkStream stream = client.GetStream();byte[] buffer = new byte[4096];while (!token.IsCancellationRequested){try{int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token);if (bytesRead == 0) break;string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);Debug.Log($"Received: {message}");sendEvent?.Invoke(message);}catch (Exception ex){Debug.LogError($"Error reading from client: {ex.Message}");break;}await Task.Delay(10, token);}}// Cleanup on client disconnectconnectedClients.Remove(client);}public void StopServer(){if (cts != null){cts.Cancel();if (tcpListener != null){tcpListener.Stop();tcpListener = null;}cts.Dispose();cts = null;}// Ensure that all connected clients are closed properlyforeach (var client in connectedClients){client.Close();}connectedClients.Clear();}
}
MyClient
类是一个简单的客户端实现,能够与 TCP 服务器进行通信。它提供了连接服务器、发送命令以及关闭连接等基本功能。
using System.Collections;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;public class MyClient
{private TcpClient client;private NetworkStream stream;private static MyClient _ins; // 单例实例private static bool connected = false;public static MyClient ins{get{if (_ins == null){_ins = new MyClient();}return _ins;}}// 私有构造函数,防止外部实例化private MyClient(){}public void Init(){if (!connected){connected = true;var path = Path.Combine(Application.streamingAssetsPath, "IpFile.txt");var p = Path.Combine(Application.streamingAssetsPath, "MyPort.txt");if (!File.Exists(p) || !File.Exists(path)) return;Debug.Log($"Reading IP configuration from: {path}");Debug.Log($"Reading port from: {p}");var ipAddress = File.ReadAllText(path, Encoding.UTF8);var port = File.ReadAllText(p, Encoding.UTF8);Debug.Log(ipAddress);Debug.Log(port);ConnectToServer(ipAddress, int.Parse(port));}}private async void ConnectToServer(string ip, int port){int maxRetryAttempts = 5; // 最大重试次数int retryDelayMilliseconds = 1500; // 重试间隔,单位为毫秒for (int attempt = 1; attempt <= maxRetryAttempts; attempt++){try{client = new TcpClient();await client.ConnectAsync(ip, port); // 异步连接服务器stream = client.GetStream();Debug.Log("Connected to server.");return; // 成功连接则退出方法}catch (SocketException e){Debug.LogError($"Attempt {attempt} failed to connect: {e.Message}");if (attempt < maxRetryAttempts){Debug.Log($"Retrying in {retryDelayMilliseconds / 1000} seconds...");await Task.Delay(retryDelayMilliseconds); // 等待重试}else{Debug.LogError("Max retry attempts reached. Unable to connect to server.");}}}}public async Task SendCommand(string command){if (stream != null && client.Connected){try{byte[] data = Encoding.UTF8.GetBytes(command);await stream.WriteAsync(data, 0, data.Length); // 发送数据到服务器Debug.Log($"Command sent: {command}");}catch (SocketException e){Debug.LogError($"Error sending command: {e.Message}");}}else{Debug.LogWarning("Not connected to server.");}}public void CloseConnection(){if (stream != null){stream.Close();stream = null;}if (client != null){client.Close();client = null;}Debug.Log("Connection closed.");}
}
相关文章:
Unity中的简易TCP服务器/客户端
在本文中,我将向你介绍一个在Unity中实现的简单TCP服务器脚本,和一个简单的客户端脚本. 脚本 MyTcpServer 允许Unity应用创建一个TCP服务器,监听客户端的连接、异步处理客户端消息,并通过事件与Unity应用中的其他模块进行通信。 MyTcpServe…...
Spring Boot 3.4 正式发布,结构化日志!
1 从 Spring Boot 3.3 升级到 3.4 1.1 RestClient 和 RestTemplate 新增对 RestClient 和 RestTemplate 自动配置的支持,可用 Reactor Netty 的 HttpClient 或 JDK 的 HttpClient。支持的客户端优先级: Apache HTTP Components (HttpComponentsClient…...

技术文档,they are my collection!
工作 今天这篇文章,献给一直撰写技术文档的自己。我自认为是公司中最爱写文档的人了,我们是一个不到40人的小公司,公司作风没有多么严谨,领导也不会要求我们写技术文档。但是从入职初至今,我一直保持着写技术文档…...
详解Qt之QtMath Qt数学类
文章目录 QtMath详解前言QtMath简介QtMath中的函数1. 三角函数1.1 qSin1.2 qCos 2. 指数与对数函数2.1 qExp2.2 qLn 3. 幂运算与平方根3.1 qPow3.2 qSqrt QtMath的优势1. 一致性与跨平台支持2. 与Qt生态系统集成3. 简洁性 总结 QtMath详解 前言 在C的开发中,数学运…...

人工智能与人类:共创未来的新篇章
数年前,当人工智能还停留在实验室的时候,很少有人能想到它会如此迅速地融入我们的日常生活。如今,从手机上的语音助手,到自动驾驶汽车,从智能家居到医疗诊断,AI的身影无处不在。这让我想起了20世纪初电力普…...

4.6 JMeter HTTP信息头管理器
欢迎大家订阅【软件测试】 专栏,开启你的软件测试学习之旅! 文章目录 前言1 HTTP信息头管理器的位置2 常见的HTTP请求头3 添加 HTTP 信息头管理器4 应用场景 前言 在 JMeter 中,HTTP信息头管理器(HTTP Header Manager)…...

非交换几何与黎曼ζ函数:数学中的一场革命性对话
非交换几何与黎曼ζ函数:数学中的一场革命性对话 非交换几何(Noncommutative Geometry, NCG)是数学的一个分支领域,它将经典的几何概念扩展到非交换代数的框架中。非交换代数是一种结合代数,其中乘积不是交换性的&…...
【设计模式】【行为型模式(Behavioral Patterns)】之观察者模式(Observer Pattern)
1. 设计模式原理说明 观察者模式(Observer Pattern) 是一种行为设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式非常适合处理事件驱动系统&a…...
文件导入-使用java反射修改日期数据
文件导入时,时间类型通常不能直接导出,以下方法为批量处理类中日期类型转字符串类型。 Date/Datetime --> String(yyyy-mm-dd)Field[] declaredFields HrAviationstudentMonitorDTO.class.getDeclaredFields(); for (Field field : declaredFields) …...
【网络安全设备系列】10、安全审计系统
0x00 定义: 网络安全审计系统针对互联网行为提供有效的行为审计、内容审计、行为报警、行为控制及相关审计功能。从管理层面提供互联网的 有效监督,预防、制止数据泄密。满足用户对互联网行为审计备案及 安全保护措施的要求,提供完整的上网记录…...
Apache Maven Assembly 插件简介
Apache Maven Assembly 插件是一个强大的工具,允许您以多种格式(如 ZIP、TAR 和 JAR)创建项目的分发包。 该插件特别适用于将项目与其依赖项、配置文件和其他必要资源一起打包。 通过使用 Maven Assembly 插件,您可以将项目作为…...

ReentrantLock(可重入锁) Semaphore(信号量) CountDownLatch
目录 ReentrantLock(可重入锁) &Semaphore(信号量)&CountDownLatchReentrantLock(可重入锁)既然有了synchronized,为啥还要有ReentrantLock?Semaphore(信号量)如何确保线程安全呢?CountDownLatch ReentrantLock(可重入锁) &Semaphore(信号量…...
计算机网络习题解答--个人笔记(未完)
本篇文章为关于《计算机网络-自顶向下方法第七版》的阅读总结和课后习题解答(未完待续) 第二章: cookie:(这里是比较老版本的HTTP,具体HTTPs是怎么实现的不是很清楚)cookie的原理其实很简单。就是在HTTP消息头上又多…...
java虚拟机——频繁发生Full GC的原因有哪些?如何避免发生Full GC
什么是Full GC Full GC(Full Garbage Collection)是Java垃圾收集过程中的一种形式,它涉及整个堆内存(包括年轻代和老年代)以及方法区的垃圾收集。Full GC是一个相对重量级的操作,因为它需要遍历和回收整个…...
python学习笔记(12)算法(5)迭代与递归
一、迭代 迭代(iteration)是一种重复执行某个任务的控制结构。在迭代中,程序会在满足一定的条件下重复执行某段代码,直到这个条件不再满足。 迭代通常用于解决需要逐步推进的计算问题,例如遍历数组、计算阶乘等。迭代…...

从零开始:Linux 环境下的 C/C++ 编译教程
个人主页:chian-ocean 文章专栏 前言: GCC(GNU Compiler Collection)是一个功能强大的编译器集合,支持多种语言,包括 C 和 C。其中 gcc 用于 C 语言编译,g 专用于 C 编译。 Linux GCC or G的安…...
Rust学习(十):计算机科学简述
Rust学习(十):计算机科学简述 在计算机技术这片广袤的领域中,深入理解其内在机制与逻辑需要付出诸多努力。 学习基础知识是构建计算机技术能力大厦的基石,而这一过程往往漫长而艰辛。只有在对基础知识有了扎实的掌握…...
【西瓜书】剪枝与样本值处理——预剪枝、后剪枝、连续值、缺失值
目录 预剪枝 后剪枝 处理连续值 处理缺失值 剪枝(pruning)是决策树学习算法对付“过拟合”的主要手段。 在决策树学习过程中,有时会造成决策树分枝过多,就可能造成过拟合,可通过主动去掉一些分支来降低过离合的风…...

NLP 1、人工智能与NLP简介
人人都不看好你,可偏偏你最争气 —— 24.11.26 一、AI和NLP的基本介绍 1.人工智能发展流程 弱人工智能 ——> 强人工智能 ——> 超人工智能 ① 弱人工智能 人工智能算法只能在限定领域解决特定的问题 eg:特定场景下的文本分类、垂直领域下的对…...
常见线程安全问题之Double Checked Locking
创作内容丰富的干货文章很费心力,感谢点过此文章的读者,点一个关注鼓励一下作者,激励他分享更多的精彩好文,谢谢大家! 双重锁定检查(Double Checked Locking,下称 DCL)是并发下实现懒…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

Linux-进程间的通信
1、IPC: Inter Process Communication(进程间通信): 由于每个进程在操作系统中有独立的地址空间,它们不能像线程那样直接访问彼此的内存,所以必须通过某种方式进行通信。 常见的 IPC 方式包括&#…...
2.2.2 ASPICE的需求分析
ASPICE的需求分析是汽车软件开发过程中至关重要的一环,它涉及到对需求进行详细分析、验证和确认,以确保软件产品能够满足客户和用户的需求。在ASPICE中,需求分析的关键步骤包括: 需求细化:将从需求收集阶段获得的高层需…...

在Zenodo下载文件 用到googlecolab googledrive
方法:Figshare/Zenodo上的数据/文件下载不下来?尝试利用Google Colab :https://zhuanlan.zhihu.com/p/1898503078782674027 参考: 通过Colab&谷歌云下载Figshare数据,超级实用!!࿰…...

理想汽车5月交付40856辆,同比增长16.7%
6月1日,理想汽车官方宣布,5月交付新车40856辆,同比增长16.7%。截至2025年5月31日,理想汽车历史累计交付量为1301531辆。 官方表示,理想L系列智能焕新版在5月正式发布,全系产品力有显著的提升,每…...
智能体革命:企业如何构建自主决策的AI代理?
OpenAI智能代理构建实用指南详解 随着大型语言模型(LLM)在推理、多模态理解和工具调用能力上的进步,智能代理(Agents)成为自动化领域的新突破。与传统软件仅帮助用户自动化流程不同,智能代理能够自主执行工…...
Qt学习及使用_第1部分_认识Qt---Qt开发基本流程
前言 学以致用,通过QT框架的学习,一边实践,一边探索编程的方方面面. 参考书:<Qt 6 C开发指南>(以下称"本书") 标识说明:概念用粗体倾斜.重点内容用(加粗黑体)---重点内容(红字)---重点内容(加粗红字), 本书原话内容用深蓝色标识,比较重要的内容用加粗倾…...