Unity使用webSocket与服务器通信(三)——C#服务端(Fleck)与Unity客户端( NativeWebSocket)传输多种数据数据
创始人
2025-06-01 13:13:41
0

一、通信时会传输哪些内容

  • 1、字符串数据
    简单的字符串:比如登录请求信息,登录结果返回的信息。
    用json系列化的字符串:比如上传一个表到服务器,让它写入到数据库中。
    读取文件的时候,读取的是string内容。

  • 2、二进制数据
    比如传输的是文件:例如myword.doc,myexcel.xls或者是assetboundle文件。
    比如上传实验报告,生成实验报告并下载等。
    读取文件的时候,直接读取字节码。

二、Unity(NativeWebSocket)和服务端(Fleck)怎么约定要传输的数据格式

在这里插入图片描述

1、Unity(NativeWebSocket)发送和接收信息的API有哪些?

  • 发送字符串
    SendText(string message)
  • 发送二进制
    Send(byte[] bytes)
  • 接收字符串【无】
    OnMessage(string : msg)
  • 接收二进制
    OnMessage(bytes : byte[])

2、服务器发送string和byte[]给Unity时,Unity如何处理?

  • Fleck发送string,使用Send(message:string)
  • Fleck发送二进制,使用Send(bytes:byte[])
  • Unity客户端统一使用OnMessage(bytes : byte[])进行数据的接收
    Unity需要识别这个包是什么内容:字符串指令,系列化的json字符串,不同种类的二进制文件…等等!

3、传输的数据格式

在这里插入图片描述

4、服务器和客户端信息来往说明

在这里插入图片描述

5、接收和发送的关键部分

(1)、客服端发送信息

  • 发送json文件到服务器
var jsonString = JsonUtility.ToJson(myScores); //myScores 预先定义的得分信息
websocket.SendText($"JSONSCOR{jsonString}");
  • 发送字符串指令到服务器
/// 
/// 命令字符串
/// 
/// 命令字符串
/// 
public async UniTask SendCommand(string cmdText)
{//传输时自动在前面添加[COMD]var msg = $"COMD{cmdText}";await websocket.SendText(msg);
}
  • 发送二进制文件到服务器
/// 
/// 发送文件
/// 
/// file.extend
/// byte[]数据
/// 成功与否
public async UniTask SendBinary(string fileName,byte[] data)
{Debug.Log($"即将发送数据:{fileName} {data.Length}");var rtn = false;if (fileName.Length > 30){Debug.Log("文件名不能超过30个字符");rtn = false;}else{var head = Encoding.UTF8.GetBytes("BINA");                         var fileNameBytes = Encoding.UTF8.GetBytes(fileName.PadRight(30)); var allData = new List();                                         allData.AddRange(head);             //头allData.AddRange(fileNameBytes);    //文件名称allData.AddRange(data);             //文件数据await websocket.Send(allData.ToArray());rtn = true;}return true;
}

(2)、客户端向服务器发送下载请求,并等待数据到达

  • 发送【COMDdown#shiYanBaoGao.docx】
  • 等待二进制数据下载
  • 保存文件到本地
//下载文件
downLoadBtn.onClick.AddListener(async () =>
{//【1】文件名var file = "shiYanBaoGao.docx";Debug.Log("从服务器下载文件");//COMD + down + # + shiYanBaoGao.docx//【2】请求下载实验报告var cmdText = $"COMDdown#{file}";    //[COMD][down][#][shiYanBaoGao.docx]await Connection.instance.websocket.SendText(cmdText);//【3】等待接收实验报告var data = await Connection.instance.ReceiveBinaryAsync(file);//【4】保存文件Debug.Log($"收到文件{file},大小为{data.Length}");FileSave.instance.SaveFileBytes(file,data);
});

(3)、客户端从服务器下载时的异步等待实现

客户端申请下载某个文件的时候逻辑:

  • 客户端创建下载任务
  • 客户端收到下载数据时判断是否是某个任务的下载需求,是则把收到的数据写入该任务缓冲里面
  • 下载完成后读取收到的数据,并从列表中删除该任务

任务列表的定义:

/// 
/// 下载任务列表: 客户端申请下载某个文件的时候使用。
///  private List DownFileTasks = new List();
/// 
[Serializable]
public class DownFileTask
{/// /// 任务ID/// public int taskID;/// /// 要下载的文件的名字:/// public string fileName;/// /// 下载状态:false-未下载,true-下载成功/// public bool state;/// /// 文件的数据:二进制信息/// public List data;
}

异步等待下载文件:

/// 
/// 等待接收文件
/// 
/// 文件名
/// 
public async UniTask ReceiveBinaryAsync(string fileName)
{//【1】创建下载任务var taskId = CreatTask(fileName, ref DownFileTasks);//【2】OnMessage(bytes[])+ ()=>{}中更新,收到文件,写入数据//在ParseBytes()里Debug.Log(DownFileTasks.Where(x => x.taskID == taskId).All(x => x.state));Debug.Log("开始等待下载......");//【3】等待下载await UniTask.WaitUntil(() => DownFileTasks.Where(x => x.taskID == taskId).All(x => x.state) == true);//【4】提取数据Debug.Log("提取数据......");var data = DownFileTasks.First(x => x.taskID == taskId).data;//【5】删除下载任务Debug.Log("删除下载任务......");DeleteTask(taskId, ref DownFileTasks);//【6】返回数据return data.ToArray();
}

6、客户端socket的主要事件绑定

  • 连接打开时…
  • 连接出错时…
  • 连接关闭时…
  • 收到二进制数据时…
/// 
/// 连接服务器
/// 
/// 服务器ip
/// 服务器端口号
/// 
async UniTask ConnectServer(string ip, int port)
{bool rtn = false;try{//websocket = new WebSocket("ws://192.168.0.137:8081");Debug.Log($"ws://{ip}:{port}");websocket = new WebSocket($"ws://{ip}:{port}");//连接打开时...websocket.OnOpen += () =>{hasConnected = true;userID = iptfdUsername.text;Debug.Log("Connection open!");textLog.text = $"Connection open! {Time.realtimeSinceStartup} {Environment.NewLine} {textLog.text}";websocket.SendText($"COMDname#{userID}"); //发送用户id};//连接出错时...websocket.OnError += (e) =>{Debug.Log("Error! " + e);textLog.text = $"Error:{e} {Time.realtimeSinceStartup} {Environment.NewLine} {textLog.text}";};//连接关闭时...websocket.OnClose += (e) =>{hasConnected = false;Debug.Log("连接被关闭了!");textLog.text = $"连接被关闭了! {Time.realtimeSinceStartup} {Environment.NewLine} {textLog.text}";};//收到二进制数据时...websocket.OnMessage += (bytes) =>{//解析数据ParseBytes(bytes);};//开始连接await websocket.Connect();rtn = true;}catch (Exception e){Debug.Log($"连接服务器出错:{e.Message}");textLog.text = $"连接服务器出错:{e.Message}";rtn = false;}return rtn;
}

7、服务器端socket的主要事件绑定

  • 连上时…
  • 断开时…
  • 收到字符串数据时…
  • 收到二进制数据时…
//var server = new WebSocketServer("ws://192.168.0.137:8081");  
var server = new WebSocketServer($"ws://{ip}:{port}");
server.Start(socket =>
{//连上sssocket.OnOpen = () =>{this.Invoke(new Action(() =>{//textBoxLog.Text += $"有新用户连入:{socket.ConnectionInfo.ClientIpAddress} {Environment.NewLine} {textBoxLog.Text}";AddText($"有新用户连入:{socket.ConnectionInfo.ClientIpAddress}");}));//报错的写法//textBoxLog.Text = $"有新用户连入:{socket.ConnectionInfo.ClientIpAddress} \n {textBoxLog.Text}";//SetTextLog($"有新用户连入:{socket.ConnectionInfo.ClientIpAddress}");Debug.WriteLine($"有新用户连入:{socket.ConnectionInfo.ClientIpAddress}");//回复一个信息//SendCommand(socket);};//断开socket.OnClose = () =>{Debug.WriteLine($"用户断开连接:{socket.ConnectionInfo.ClientIpAddress}");this.Invoke(new Action(() =>{AddText($"用户断开连接:{socket.ConnectionInfo.ClientIpAddress}");}));UserSockets.First(x => x.socket.ConnectionInfo.Id == socket.ConnectionInfo.Id).connected = false;};//收到string信息socket.OnMessage = message =>{Debug.WriteLine($"收到一条消息,来自:{socket.ConnectionInfo.ClientIpAddress}");Debug.WriteLine(message);this.Invoke(new Action(() =>{AddText($"收到一条消息,来自:{socket.ConnectionInfo.ClientIpAddress}");AddText($"{message}");}));//解析客户端字符串命令ParseString(message,socket);};//收到二进制信息socket.OnBinary = bytes =>{var userName = UserSockets.First(x => x.socket.ConnectionInfo.Id == socket.ConnectionInfo.Id).userID;Debug.WriteLine($"收到二进制数据,长度为{bytes.Length}Bytes,来自ip:{socket.ConnectionInfo.ClientIpAddress},userID ={userName}");this.Invoke(new Action(() =>{AddText($"收到二进制数据,长度为{bytes.Length}Bytes,来自ip:{socket.ConnectionInfo.ClientIpAddress},userID ={userName}");}));var head = Encoding.UTF8.GetString(bytes.Take(4).ToArray());switch (head){case "BINA"://收到二进制文件ParseBinaryFile(bytes,socket);break;case "other"://break;default://break;}};
});

三、todo

实时传输语音和视频

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...