当前位置: 首页 > news >正文

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.");}
}

http://www.lryc.cn/news/491892.html

相关文章:

  • Spring Boot 3.4 正式发布,结构化日志!
  • 技术文档,they are my collection!
  • 详解Qt之QtMath Qt数学类
  • 人工智能与人类:共创未来的新篇章
  • 4.6 JMeter HTTP信息头管理器
  • 非交换几何与黎曼ζ函数:数学中的一场革命性对话
  • 【设计模式】【行为型模式(Behavioral Patterns)】之观察者模式(Observer Pattern)
  • 文件导入-使用java反射修改日期数据
  • 【网络安全设备系列】10、安全审计系统
  • Apache Maven Assembly 插件简介
  • ReentrantLock(可重入锁) Semaphore(信号量) CountDownLatch
  • 计算机网络习题解答--个人笔记(未完)
  • java虚拟机——频繁发生Full GC的原因有哪些?如何避免发生Full GC
  • python学习笔记(12)算法(5)迭代与递归
  • 从零开始:Linux 环境下的 C/C++ 编译教程
  • Rust学习(十):计算机科学简述
  • 【西瓜书】剪枝与样本值处理——预剪枝、后剪枝、连续值、缺失值
  • NLP 1、人工智能与NLP简介
  • 常见线程安全问题之Double Checked Locking
  • Redis(非关系型数据库)的作用 详细解读
  • 互联网视频推拉流EasyDSS视频直播点播平台视频转码有哪些技术特点和应用?
  • python之多元线性回归
  • 学习threejs,使用设置lightMap光照贴图创建阴影效果
  • 一,SQL注入解题(猫舍)
  • 海康大华宇视视频平台EasyCVR私有化部署视频平台海康ISUP是什么?如何接入到EasyCVR?
  • Java ArrayList 与顺序表:在编程海洋中把握数据结构的关键之锚
  • windows下安装wsl的ubuntu,同时配置深度学习环境
  • 开展网络安全成熟度评估:业务分析师的工具和技术
  • Maven Surefire 插件简介
  • 基于微信小程序的平价药房管理系统+LW参考示例