零、常用数据类型占用字节数
- bool - 占用1个字节,用于存储真(true)或假(false)值。
- byte - 占用1个字节,表示无符号的8位整数,范围从0到255。
- char - 占用2个字节,表示一个Unicode字符。
- short - 占用2个字节,表示有符号的16位整数,范围从-32,768到32,767。
- int - 占用4个字节,表示有符号的32位整数,范围从-2,147,483,648到2,147,483,647。
- long - 占用8个字节,表示有符号的64位整数,范围从-9,223,372,036,854,775,808到9,223,372,036,854,775,807。
- float - 占用4个字节,表示单精度32位IEEE 754浮点数。
- double - 占用8个字节,表示双精度64位IEEE 754浮点数。
一、Unity数据发送
- 上一章unity webgl联机游戏【1.全网最细的WebSocket库安装图文教程】有涉及到Unity的程序,这一章就在上一章基础上添加代码
- unity中发送数据仅需要通过
ws.Send()
语句即可完成发送,但ws.Send()
发送的是byte[]字节串,所以需要对数据进行序列化,下面是几个比较常见的数据类型序列化
1. String类
ws.Send(Encoding.UTF8.GetBytes("需要发的字符串"));
2. Int类
- 如果你的Int数据有包含负数或>255,需要包含4个字节,即通过int32进行发送,这时候就要用到BitConverter
int data=1000;
byte[] sendData = BitConverter.GetBytes(data);
ws.Send(sendData);
- 如果你要发送的Int始终不大于255,那可以节省一下,直接强制转化为byte
int data=1;
byte[] sendData = new byte[1];
sendData[0]=(byte)data;
ws.Send(sendData);
3. bool、float、double
- 均可用
BitConverter.GetBytes()
进行序列化
4. 数据连接
Buffer.BlockCopy(A, 0, B,X,A.Length );
- 这表示从B中的X位开始,把A添加到B上
- 完整实例如下:
// 要发送的数据1
int intData=1000;
byte[] intDataByte= BitConverter.GetBytes(intData);
// 要发送的数据2
float floatData=100.0;
byte[] floatDataByte= BitConverter.GetBytes(floatData);
// 要发送的所有数据
byte[] sendData= new byte[8];
Buffer.BlockCopy(intDataByte, 0, sendData, 0, 4);
Buffer.BlockCopy(floatDataByte, 0, sendData, 4, 4);
ws.Send(sendData);
二、Python数据接收解码
import asyncio
import websockets
import struct
async def echo(websocket):
try:
async for data in websocket:
print(data)
except websockets.exceptions.ConnectionClosed:
print("连接已关闭")
async def main():
async with websockets.serve(echo, "0.0.0.0", 80):
await asyncio.Future()
asyncio.run(main())
这是上一章中的代码,值得注意的是,这个代码是异步的,可以同时处理多个WebSocket连接。其中Data
接收的是原始数据,需要对其进行反序列化。
- python反序列化可以通过
struct.unpack()
实现
intData = struct.unpack('i', data[:4])[0]
- 如上面这段代码对unity发送的数据进行了反序列化,具体功能是:取出数据包前四个字节,然后反序列化为int类型的数据
- 其中的第一个参数是表示需要解包成什么数据,fmt表如下
- 当然如果你用单个字节传的数据,也可以直接强制转化,比如:假设我直接用byte传了个int类型的数据:PlayerId=1
PlayerId=int(data[0])
三、Python数据发送
通过await websocket.send()
语句发送
1. 序列化
- 和接收类似,直接用
struct.pack()
即可 - 例如我要发送一个int类型的数据
data=1
sendData=struct.pack('i',data)
await websocket.send(sendData)
2. 数据连接
- 如果你的数据存在一个数组内,可以通过
.join
直接连接发送
data=[b'1',b'2']
concatenated_data = b''.join(data)
await websocket.send(concatenated_data)
- 如果不是,可以通过
+=
实现
data=b'1'
concatenated_data=b''
concatenated_data+=data
await websocket.send(concatenated_data)
四、unity接收
- Unity的接收在
ws.OnMessage += (byte[] msg) =>{}
内,msg就是收到的原始数据 - 值得注意的是当msg没有被访问完时,又收到了下一帧数据,就会有报错:
An exception has occurred during an OnMessage event.
;而且这个时候你的回调里会有一些程序没有被执行,所以尽量不要在这个回调里做一些耗时运算,比如查找游戏对象等等;
反序列化
其中A表示从msg中的第几位开始读取
- int型
int data=BitConverter.ToInt32(msg, A);
如果是用单字节传递的,也可以使用(int)
int data=(int)msg[A];
- float型
float data=BitConverter.ToSingle(msg,A);
- bool型
bool data=BitConverter.ToBoolean(msg,A);