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)是并发下实现懒…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...
算法—栈系列
一:删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...
网页端 js 读取发票里的二维码信息(图片和PDF格式)
起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的ÿ…...
虚幻基础:角色旋转
能帮到你的话,就给个赞吧 😘 文章目录 移动组件使用控制器所需旋转:组件 使用 控制器旋转将旋转朝向运动:组件 使用 移动方向旋转 控制器旋转和移动旋转 缺点移动旋转:必须移动才能旋转,不移动不旋转控制器…...
使用python进行图像处理—图像滤波(5)
图像滤波是图像处理中最基本和最重要的操作之一。它的目的是在空间域上修改图像的像素值,以达到平滑(去噪)、锐化、边缘检测等效果。滤波通常通过卷积操作实现。 5.1卷积(Convolution)原理 卷积是滤波的核心。它是一种数学运算,…...
