1 同步与异步
同步方法
方法中逻辑执行完毕后,再继续执行后面的方法。
异步方法
方法中逻辑可能还没有执行完毕,就继续执行后面的内容。
往往异步方法当中都会使用多线程执行某部分逻辑,因为不需要等待方法中逻辑执行完毕就可以继续执行下面的逻辑。
注意
Unity 中协同程序中的某些异步方法,有的使用的是多线程,有的使用的是迭代器分步执行。
2 常用异步方法
2.1 Beign / End 方法
IAsyncResult
IAsyncResult 接口由包含可异步作的方法的类实现,是启动异步作的方法的返回类型。
当异步调用完成时,将向 WaitHandle 发出信号,可以通过调用 WaitOne 方法来等待它。

AsyncState
:调用异步方法时传入的参数,需要转换为传入的参数类型。AsyncWaitHandle
:用于同步等待。CompletedSynchronously
:异步操作是否同步完成。IsCompleted
:异步操作是否完成。
BeginConnect() / EndConnect()
BeginConnect()
当调用BeginConnect
方法时,该方法立即返回一个IAsyncResult
对象,而不会等待连接完成。调用者可以继续执行其他操作,直到连接操作完成,然后通过EndConnect
方法获取连接结果。

remoteEP
:表示远程主机的终结点(EndPoint)。callback
:表示异步操作完成时要调用的回调方法。state
:表示与异步操作关联的状态对象,可以是任何对象(通常传递 Socket 实例)。address
:表示远程主机的 IP 地址。port
:表示远程主机的端口号。requestCallback
:表示异步操作完成时要调用的回调方法。host
:表示远程主机的域名或 IP 地址。
EndConnect()
通常与BeginConnect
方法成对使用。

public class Lesson12 : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
var socketTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketTcp.BeginAccept(AcceptCallBack, socketTcp);
var ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
socketTcp.BeginConnect(ipPoint, result =>
{
Socket s = result.AsyncState as Socket;
try
{
s.EndConnect(result);
print("连接成功!");
}
catch (SocketException e)
{
print("连接出错:" + e.SocketErrorCode + e.Message);
}
}, socketTcp);
}
private void AcceptCallBack(IAsyncResult result)
{
...
}
}
BeginAccept() / EndAccept()
BeginAccept()
异步开始接受传入的连接请求,避免阻塞主线程。需传入回调函数和状态对象(通常是原始 Socket 实例)。

callback
:连接建立后的回调函数。state
:状态对象(通常是原始 Socket 实例)。receiveSize
:缓冲区大小。acceptSocket
:接受套接字。
EndAccept()
在回调函数中调用,用于完成异步连接操作并返回新的客户端 Socket。
会返回一个新的 Socket 实例,用于与客户端通信。

buffer
:输出参数,用于接收客户端发送的数据。这个缓冲区的大小应该足够大,以容纳客户端发送的数据。asyncResult
:IAsyncResult
对象,表示异步操作的状态。bytesTransferred
:输出参数,用于返回实际传输的字节数。
public class Lesson12 : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
var socketTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
...
socketTcp.BeginAccept(AcceptCallBack, socketTcp);
}
private void AcceptCallBack(IAsyncResult result)
{
try
{
// 获取传入的参数
Socket s = result.AsyncState as Socket;
// 通过调用 EndAccept 得到连入的客户端 Socket
Socket clientSocket = s.EndAccept(result);
// do something with clientSocket
// ...
}
catch (SocketException e)
{
print(e.SocketErrorCode);
}
}
}
BeginSend() / EndSend()
BeginSend()

buffer
:接收数据的缓冲区。offset
:缓冲区中开始接收数据的偏移量。size
:要接收的最大字节数。socketFlags
:控制接收操作的标志。errorCode
:输出参数,表示操作的结果。callback
:异步操作完成时调用的回调方法。state
:与异步操作关联的用户状态对象。
EndSend()

public class Lesson12 : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
...
var bytes = Encoding.UTF8.GetBytes("1231231231223123123");
socketTcp.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, (result) =>
{
try
{
socketTcp.EndSend(result);
print("发送成功");
}
catch (SocketException e)
{
print("发送错误" + e.SocketErrorCode + e.Message);
}
}, socketTcp);
}
}
BeginReceive() / EndReceive()
BeginReceive()

EndReceive()

public class Lesson12 : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
...
socketTcp.BeginReceive(_resultBytes, 0, _resultBytes.Length, SocketFlags.None, ReceiveCallBack, socketTcp);
}
private void ReceiveCallBack(IAsyncResult result)
{
try
{
Socket s = result.AsyncState as Socket;
// 这个返回值是你受到了多少个字节
int num = s.EndReceive(result);
// 进行消息处理
Encoding.UTF8.GetString(_resultBytes, 0, num);
// 我还要继续接受
s.BeginReceive(_resultBytes, 0, _resultBytes.Length, SocketFlags.None, ReceiveCallBack, s);
}
catch (SocketException e)
{
print("接受消息处问题" + e.SocketErrorCode + e.Message);
}
}
}
2.2 Async 方法
Async 方法相比于 Begin / End 方法,参数相对少一些。主要参数配置集中在 SocketAsyncEventArgs
中,该类封装了异步操作所需的参数和结果。
ConnectAsync()

SocketType
和ProtocolType
参数用于指定 Socket 的类型和协议。SocketAsyncEventArgs
对象e
包含了连接所需的参数。
public class Lesson12 : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
...
SocketAsyncEventArgs e2 = new SocketAsyncEventArgs();
e2.Completed += (socket, args) =>
{
if (args.SocketError == SocketError.Success)
{
//连接成功
}
else
{
//连接失败
print(args.SocketError);
}
};
socketTcp.ConnectAsync(e2);
}
}
AcceptAsync()

public class Lesson12 : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
...
var e = new SocketAsyncEventArgs();
e.Completed += (socket, args) =>
{
//首先判断是否成功
if (args.SocketError == SocketError.Success)
{
//获取连入的客户端socket
Socket clientSocket = args.AcceptSocket;
(socket as Socket).AcceptAsync(args);
}
else
{
print("连入客户端失败" + args.SocketError);
}
};
socketTcp.AcceptAsync(e);
}
}
SendAsync()
发送前需要调用 SocketAsyncEventArgs
的 SetBuffer()
方法设置发送数组。

public class Lesson12 : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
...
var e3 = new SocketAsyncEventArgs();
var bytes2 = Encoding.UTF8.GetBytes("123123的就是拉法基萨克两地分居");
e3.SetBuffer(bytes2, 0, bytes2.Length);
e3.Completed += (socket, args) =>
{
if (args.SocketError == SocketError.Success)
{
print("发送成功");
}
else
{ }
};
socketTcp.SendAsync(e3);
}
}
ReceiveAsync()
接收也需要调用 SocketAsyncEventArgs
的 SetBuffer()
方法设置接收到哪个数组中。

public class Lesson12 : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
...
var e4 = new SocketAsyncEventArgs();
// 设置接受数据的容器,偏移位置,容量
e4.SetBuffer(new byte[1024 * 1024], 0, 1024 * 1024);
e4.Completed += (socket, args) =>
{
if (args.SocketError == SocketError.Success)
{
// 收取存储在容器当中的字节
// Buffer 是容器
// BytesTransferred 是收取了多少个字节
Encoding.UTF8.GetString(args.Buffer, 0, args.BytesTransferred);
// 接收完消息 再接收下一条
args.SetBuffer(0, args.Buffer.Length);
(socket as Socket).ReceiveAsync(args);
}
else
{ }
};
socketTcp.ReceiveAsync(e4);
}
}
3 实战
3.1 服务端配置
依次创建如下 3 个脚本:
- ClientSocket.cs
- ServerSocket.cs
- Program.cs
3.1.1 ClientSocket.cs
- 异步连接管理:自动为每个客户端连接分配唯一 ID,并立即开始异步接收消息。
- 异步消息发送:提供
Send()
方法异步发送字符串消息到服务器。 - 异步消息接收:通过回调机制持续接收服务器发送的消息。
- 错误处理:捕获并处理套接字操作中的异常。
1)成员变量
private static int _BeginId = 1; // 静态ID计数器
public Socket Client { get; private set; } // 底层Socket对象
public int Id { get; set; } // 客户端唯一标识
private byte[] _buffer = new byte[1024]; // 接收缓冲区
private int _bufferOffset = 0; // 缓冲区偏移量
2)构造函数
构造函数接收一个已连接的 Socket 对象,为其分配 ID,并立即开始异步接收数据。
public ClientSocket(Socket client)
{
Client = client;
Id = _BeginId++; // 分配唯一ID
// 立即开始异步接收消息
Client.BeginReceive(_buffer, _bufferOffset, _buffer.Length - _bufferOffset,
SocketFlags.None, ReceiveCallback, Client);
}
3)消息发送
Send()
方法将字符串编码为 UTF-8 字节数组,然后异步发送。
public void Send(string message)
{
try
{
var bytes = Encoding.UTF8.GetBytes(message);
Client.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, SendCallback, Client);
}
catch (SocketException e)
{
Console.WriteLine($"客户端 Id 发送消息时发生错误:e.Message");
}
}
4)发送回调
发送完成后调用此回调,处理发送结果。
private void SendCallback(IAsyncResult ar)
{
try
{
var client = (Socket) ar.AsyncState!;
client.EndSend(ar); // 完成异步发送
}
catch (SocketException e)
{
Console.WriteLine($"客户端 Id 发送消息时发生错误:e.Message");
}
}
5)接收回调
这是核心的接收逻辑,处理接收到的数据并保持持续接收状态。
private void ReceiveCallback(IAsyncResult ar)
{
try
{
var client = (Socket) ar.AsyncState!;
_bufferOffset = client.EndReceive(ar); // 完成接收
// 处理消息
var message = Encoding.UTF8.GetString(_buffer, 0, _bufferOffset);
Console.WriteLine($"收到客户端 {Id} 的消息:{message}");
_bufferOffset = 0; // 重置缓冲区
if (client.Connected)
{
// 继续接收下一条消息
client.BeginReceive(_buffer, _bufferOffset, _buffer.Length - _bufferOffset,
SocketFlags.None, ReceiveCallback, client);
}
else
{
Console.WriteLine($"客户端 {Id} 断开连接!");
}
}
catch (SocketException e)
{
Console.WriteLine($"客户端 {Id} 接收消息时发生错误:{e.Message}");
}
}
3.1.2 ServerSocket.cs
- 服务器管理:创建并管理 TCP 服务器套接字,监听指定 IP 和端口
- 客户端连接处理:异步接受客户端连接,为每个连接创建
ClientSocket
实例 - 消息广播:向所有已连接客户端发送消息
- 客户端管理:使用字典存储所有连接的客户端套接字
1)成员变量
public Socket Server { get; private set; } // 服务器Socket对象
private Dictionary<int, ClientSocket> _clientSockets = new(); // 存储所有客户端连接
2)启动服务器
Start()
方法初始化服务器 Socket,绑定到指定 IP 和端口,并开始监听连接请求。
public void Start(string ip, int port, int num)
{
Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var ipPoint = new IPEndPoint(IPAddress.Parse(ip), port);
Server.Bind(ipPoint);
Server.Listen(num); // 设置最大挂起连接数
Server.BeginAccept(AcceptCallback, Server); // 开始异步接受连接
}
3)接受客户端连接
这是核心的异步连接处理逻辑,使用回调机制处理新连接。
private void AcceptCallback(IAsyncResult ar)
{
var server = (Socket) ar.AsyncState!;
var client = server.EndAccept(ar); // 完成异步接受
var clientSocket = new ClientSocket(client); // 创建客户端Socket包装
_clientSockets.Add(clientSocket.Id, clientSocket); // 存储客户端
Console.WriteLine($"客户端 {clientSocket.Id} 连接成功!");
server.BeginAccept(AcceptCallback, server); // 继续接受新连接
}
4)消息广播
该方法遍历所有已连接客户端,发送相同消息。
public void BroadCast(string msg)
{
foreach (var clientSocket in _clientSockets.Values)
{
clientSocket.Send(msg); // 向每个客户端发送消息
}
}
3.1.3 Program.cs
- 服务器启动:初始化并启动 TCP 服务器。
- 交互式控制:通过控制台输入管理服务器。
- 消息广播:向所有连接客户端发送消息。
- 退出机制:提供优雅关闭服务器的选项。
1)服务器初始化
- 创建
ServerSocket
实例。 - 启动服务器监听本地回环地址(127.0.0.1)的 8080 端口。
- 设置最大挂起连接数为 10。
- 输出启动信息。
var serverSocket = new ServerSocket();
serverSocket.Start("127.0.0.1", 8080, 10);
Console.WriteLine("服务器已启动,等待客户端连接...");
2)主控制循环
这是一个无限循环,等待控制台输入并处理命令:
- exit 命令:退出循环,结束程序。
- B:前缀消息:广播消息给所有客户端(去除"B:"前缀)。
- 其他输入:当前版本忽略。
while (true)
{
var input = Console.ReadLine();
if (input == "exit")
{
break;
}
else if (input?[..2] == "B:")
{
serverSocket.BroadCast(input[2..]);
}
}
3)使用说明
- 启动服务器:运行程序即启动服务器。
- 广播消息:输入"B:消息内容"广播给所有客户端。
- 退出服务器:输入"exit"关闭服务器。
3.2 客户端配置
依次创建如下 3 个脚本:
- NetAsyncMgr.cs
- MainAsync.cs
- Lesson13.cs
3.2.1 NetAsyncMgr.cs
实现 Unity 异步 Socket 网络管理器,用于处理与服务器的 TCP 连接、消息发送和接收。
- 单例模式:通过
Instance
属性确保全局唯一访问点。 - 异步连接:使用
ConnectAsync
实现非阻塞连接。 - 消息收发:支持异步发送和接收 UTF-8 编码的字符串消息。
- 连接管理:提供连接状态检查和关闭方法。
1)初始化与连接
使用SocketAsyncEventArgs
实现异步连接,连接完成后触发ConnectCallback
回调。
public void Connect(string ip, int port)
{
var ipPoint = new IPEndPoint(IPAddress.Parse(ip), port);
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var args = new SocketAsyncEventArgs();
args.RemoteEndPoint = ipPoint;
args.Completed += ConnectCallback;
_socket.ConnectAsync(args);
}
2)消息发送
将字符串编码为 UTF-8 字节数组后异步发送,发送完成后触发SendCallback
。
public void Send(string msg)
{
var bytes = Encoding.UTF8.GetBytes(msg);
var args = new SocketAsyncEventArgs();
args.SetBuffer(bytes, 0, bytes.Length);
args.Completed += SendCallback;
_socket.SendAsync(args);
}
3)消息接收
使用循环接收模式,每次接收完成后立即开始下一次接收。
private void ReceiveCallback(object sender, SocketAsyncEventArgs e)
{
print(Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred));
socket.ReceiveAsync(e); // 继续接收下一条消息
}
3.2.2 MainAsync.cs
MainAsync.cs 用于初始化并连接网络管理器 NetAsyncMgr。
- 网络管理器初始化:确保
NetAsyncMgr
单例实例存在。 - 自动连接服务器:启动时自动连接本地 8080 端口。
1)网络管理器初始化
这段代码实现了"懒加载"模式:
- 检查
NetAsyncMgr
单例是否存在。 - 如不存在则创建新的 GameObject 并附加
NetAsyncMgr
组件。
if (NetAsyncMgr.Instance == null)
{
var go = new GameObject("NetAsyncMgr");
go.AddComponent<NetAsyncMgr>();
}
2)服务器连接
使用单例实例连接本地服务器 (127.0.0.1) 的 8080 端口。
NetAsyncMgr.Instance.Connect("127.0.0.1", 8080);
3.2.3 Lesson13.cs
- UI 组件绑定
BtnSend
:发送按钮。TMP_InputField
:文本输入框(使用 TextMeshPro 实现)。
- 消息发送逻辑
- 在
Start()
中注册按钮点击事件。 - 点击按钮时调用
NetAsyncMgr.Instance.Send()
发送输入框内容。
- 在
3.3 代码
服务端
// ------------------------------------------------------------
// @file ClientSocket.cs
// ------------------------------------------------------------
namespace NetLearningTcpServerAsync;
using System.Net.Sockets;
using System.Text;
public class ClientSocket
{
private static int _BeginId = 1;
public Socket Client { get; private set; }
public int Id { get; set; }
private byte[] _buffer = new byte[1024];
private int _bufferOffset = 0;
public ClientSocket(Socket client)
{
Client = client;
Id = _BeginId++;
// 开始收消息
Client.BeginReceive(_buffer, _bufferOffset, _buffer.Length - _bufferOffset, SocketFlags.None, ReceiveCallback, Client);
}
public void Send(string message)
{
try
{
var bytes = Encoding.UTF8.GetBytes(message);
Client.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, SendCallback, Client);
}
catch (SocketException e)
{
Console.WriteLine($"客户端 Id 发送消息时发生错误:e.Message");
}
}
private void SendCallback(IAsyncResult ar)
{
try
{
var client = (Socket) ar.AsyncState!;
client.EndSend(ar);
}
catch (SocketException e)
{
Console.WriteLine($"客户端 Id 发送消息时发生错误:e.Message");
}
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
var client = (Socket) ar.AsyncState!;
_bufferOffset = client.EndReceive(ar);
// 处理收到的消息
var message = Encoding.UTF8.GetString(_buffer, 0, _bufferOffset);
Console.WriteLine($"收到客户端 {Id} 的消息:{message}");
// 清空缓冲区
_bufferOffset = 0;
if (client.Connected)
{
// 继续接收消息
client.BeginReceive(_buffer, _bufferOffset, _buffer.Length - _bufferOffset, SocketFlags.None, ReceiveCallback, client);
}
else
{
Console.WriteLine($"客户端 {Id} 断开连接!");
}
}
catch (SocketException e)
{
Console.WriteLine($"客户端 {Id} 接收消息时发生错误:{e.Message}");
}
}
}
// ------------------------------------------------------------
// @file ServerSocket.cs
// ------------------------------------------------------------
namespace NetLearningTcpServerAsync;
using System.Net;
using System.Net.Sockets;
public class ServerSocket
{
public Socket Server { get; private set; }
private Dictionary<int, ClientSocket> _clientSockets = new();
public void Start(string ip, int port, int num)
{
Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var ipPoint = new IPEndPoint(IPAddress.Parse(ip), port);
try
{
Server.Bind(ipPoint);
Server.Listen(num);
Server.BeginAccept(AcceptCallback, Server);
}
catch (SocketException e)
{
Console.WriteLine(e);
throw;
}
}
public void BroadCast(string msg)
{
foreach (var clientSocket in _clientSockets.Values)
{
clientSocket.Send(msg);
}
}
private void AcceptCallback(IAsyncResult ar)
{
try
{
var server = (Socket) ar.AsyncState!;
var client = server.EndAccept(ar);
var clientSocket = new ClientSocket(client);
_clientSockets.Add(clientSocket.Id, clientSocket);
Console.WriteLine($"客户端 {clientSocket.Id} 连接成功!");
// 继续让别的客户端连入
server.BeginAccept(AcceptCallback, server);
}
catch (SocketException e)
{
Console.WriteLine(e);
throw;
}
}
}
// ------------------------------------------------------------
// @file Program.cs
// ------------------------------------------------------------
using NetLearningTcpServerAsync;
var serverSocket = new ServerSocket();
serverSocket.Start("127.0.0.1", 8080, 10);
Console.WriteLine("服务器已启动,等待客户端连接...");
while (true)
{
var input = Console.ReadLine();
if (input == "exit")
{
break;
}
else if (input?[..2] == "B:")
{
serverSocket.BroadCast(input[2..]);
}
}
客户端
// ------------------------------------------------------------
// @file NetAsyncMgr.cs
// ------------------------------------------------------------
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
public class NetAsyncMgr : MonoBehaviour
{
public static NetAsyncMgr Instance { get; private set; }
private Socket _socket; // 连接服务器的 Socket
private byte[] _buffer = new byte[1024 * 1024];
private int _bufferOffset = 0;
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
}
public void Connect(string ip, int port)
{
if (_socket != null && _socket.Connected)
{
return;
}
var ipPoint = new IPEndPoint(IPAddress.Parse(ip), port);
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var args = new SocketAsyncEventArgs();
args.RemoteEndPoint = ipPoint;
args.Completed += ConnectCallback;
_socket.ConnectAsync(args);
}
public void Send(string msg)
{
if (_socket == null || !_socket.Connected)
{
return;
}
var bytes = Encoding.UTF8.GetBytes(msg);
var args = new SocketAsyncEventArgs();
args.SetBuffer(bytes, 0, bytes.Length);
args.Completed += SendCallback;
_socket.SendAsync(args);
}
public void Close()
{
if (_socket != null)
{
_socket.Shutdown(SocketShutdown.Both);
_socket.Disconnect(false);
_socket.Close();
_socket = null;
}
}
private void SendCallback(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
Debug.Log("Send Success");
}
else
{
Debug.Log("Send Failed: " + e.SocketError);
Close();
}
}
private void ConnectCallback(object sender, SocketAsyncEventArgs eventArgs)
{
if (eventArgs.SocketError == SocketError.Success)
{
Debug.Log("Connect Success");
var socket = sender as Socket;
if (socket == null || !socket.Connected)
{
return;
}
// TODO: 连接成功后,开始接收数据
var args2 = new SocketAsyncEventArgs();
args2.SetBuffer(_buffer, 0, _buffer.Length);
args2.Completed += ReceiveCallback;
socket.ReceiveAsync(args2);
}
else
{
Debug.Log("Connect Failed: " + eventArgs.SocketError);
}
}
private void ReceiveCallback(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
print(Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred));
// TODO: 处理接收到的数据
var socket = sender as Socket;
if (socket == null || !socket.Connected)
{
return;
}
// 继续接收数据
socket.ReceiveAsync(e);
}
else
{
print("接受消息出错:" + e.SocketError);
Close();
}
}
}
// ------------------------------------------------------------
// @file MainAsync.cs
// ------------------------------------------------------------
using UnityEngine;
public class MainAsync : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
if (NetAsyncMgr.Instance == null)
{
var go = new GameObject("NetAsyncMgr");
go.AddComponent<NetAsyncMgr>();
}
NetAsyncMgr.Instance.Connect("127.0.0.1", 8080);
}
}
// ------------------------------------------------------------
// @file Lesson13.cs
// ------------------------------------------------------------
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class Lesson13 : MonoBehaviour
{
public Button BtnSend;
public TMP_InputField TxtMessage;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
BtnSend.onClick.AddListener(() =>
{
NetAsyncMgr.Instance.Send(TxtMessage.text);
});
}
}
4 测试
- Unity 中创建新场景,新建空物体 Main,将 MainAsync.cs 脚本挂载上去。

- 创建 Canvas 画布,添加 InputField 和 Button 并关联至 Lesson13.cs。

- 首先运行服务器。

服务器启动后,运行 Unity。服务器显示连接成功。
输入命令“B:Hello!”,回车。

- Unity 中接收到消息并输出。

- Unity 中在 InputField 中输入文字,点击发送。

- 服务器中接收到了消息并打印输出。

到此,完成了服务器和客户端的双向通信。