Unity使用webSocket与服务器通信——C#服务端(Fleck)与Unity客户端( NativeWebSocket)传输多种数据数据
Posted dzj2021
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity使用webSocket与服务器通信——C#服务端(Fleck)与Unity客户端( NativeWebSocket)传输多种数据数据相关的知识,希望对你有一定的参考价值。
一、通信时会传输哪些内容
-
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($"JSONSCORjsonString");
- 发送字符串指令到服务器
/// <summary>
/// 命令字符串
/// </summary>
/// <param name="text">命令字符串</param>
/// <returns></returns>
public async UniTask SendCommand(string cmdText)
//传输时自动在前面添加[COMD]
var msg = $"COMDcmdText";
await websocket.SendText(msg);
- 发送二进制文件到服务器
/// <summary>
/// 发送文件
/// </summary>
/// <param name="file">file.extend</param>
/// <param name="data">byte[]数据</param>
/// <returns>成功与否</returns>
public async UniTask<bool> 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<byte>();
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)、客户端从服务器下载时的异步等待实现
客户端申请下载某个文件的时候逻辑:
- 客户端创建下载任务
- 客户端收到下载数据时判断是否是某个任务的下载需求,是则把收到的数据写入该任务缓冲里面
- 下载完成后读取收到的数据,并从列表中删除该任务
任务列表的定义:
/// <summary>
/// 下载任务列表: 客户端申请下载某个文件的时候使用。
/// private List<DownFileTask> DownFileTasks = new List<DownFileTask>();
/// </summary>
[Serializable]
public class DownFileTask
/// <summary>
/// 任务ID
/// </summary>
public int taskID;
/// <summary>
/// 要下载的文件的名字:
/// </summary>
public string fileName;
/// <summary>
/// 下载状态:false-未下载,true-下载成功
/// </summary>
public bool state;
/// <summary>
/// 文件的数据:二进制信息
/// </summary>
public List<byte> data;
异步等待下载文件:
/// <summary>
/// 等待接收文件
/// </summary>
/// <param name="fileName">文件名</param>
/// <returns></returns>
public async UniTask<byte[]> 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的主要事件绑定
- 连接打开时…
- 连接出错时…
- 连接关闭时…
- 收到二进制数据时…
/// <summary>
/// 连接服务器
/// </summary>
/// <param name="ip">服务器ip</param>
/// <param name="port">服务器端口号</param>
/// <returns></returns>
async UniTask<bool> 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 =>
//连上ss
socket.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.LengthBytes,来自ip:socket.ConnectionInfo.ClientIpAddress,userID =userName");
this.Invoke(new Action(() =>
AddText($"收到二进制数据,长度为bytes.LengthBytes,来自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
实时传输语音和视频
java怎么实现与websocket服务器的通信
java怎么实现与websocket服务器的通信。
可有偿。
要求:
使用java语言
能打通通信通道即可。
不要找网上例子,例子没用。
我大约可支付软妹币100的样子。
以上是关于Unity使用webSocket与服务器通信——C#服务端(Fleck)与Unity客户端( NativeWebSocket)传输多种数据数据的主要内容,如果未能解决你的问题,请参考以下文章
java/spring 和 c++/qt 应用程序与 websockets 之间的通信