Skip to content

Instantly share code, notes, and snippets.

@MSylvia
Forked from lazalong/SimpleENetSpanTestCase.cs
Created March 12, 2019 15:22
Show Gist options
  • Save MSylvia/718124045f377885efc34d69ca29ded8 to your computer and use it in GitHub Desktop.
Save MSylvia/718124045f377885efc34d69ca29ded8 to your computer and use it in GitHub Desktop.
Simple Test Case to Send messages with ENet-Sharp & ENetStack
//
// Simple Test Case to Send messages with ENet-Sharp & ENetStack
// -------------------------------------------------------------
// steven 'lazalong' 2019
//
// If all goes smoothly you should see the followign log line:
// [Server] LogindData= OpCode= 4 passHash= 70 username= username
// UnityEngine.Debug:Log(Object)
// You will need the dll from the reference below.
// Reference:
// - https://github.com/nxrighthere/NetStack
// - https://github.com/nxrighthere/ENet-CSharp
// - Discord channel: NCoders
using System;
using System.Runtime.InteropServices;
using System.Threading;
using DisruptorUnity3d;
using ENet;
using NetStack.Serialization;
using UnityEngine;
using Event = ENet.Event;
using EventType = ENet.EventType;
// Steven 'lazalong' span test
// thanks nxrighthere for inspiration and help
public class SimpleENetSpanTestCase : MonoBehaviour
{
public int maxClients = 32;
public ushort port = 9500;
private bool isAlive = true;
private Thread serverThread;
private Thread clientThread;
private byte[] data = new byte[128];
private BitBuffer bitBuffer;
private RingBuffer<NetMessage> netMessageQueue = new RingBuffer<NetMessage>(500);
private void Start()
{
ENet.Library.Initialize();
serverThread = new Thread(Server);
serverThread.Start();
clientThread = new Thread(Client);
clientThread.Start();
}
public void Update()
{
// Treat messages
while (netMessageQueue.TryDequeue(out NetMessage netMessage))
{
Debug.Log(">>>>> Dequeue: " + netMessage.opcode);
if (netMessage.opcode == 4)
{
ReadOnlySpan<byte> span;
unsafe
{
span = new ReadOnlySpan<byte>((byte*)netMessage.data, netMessage.dataLength);
}
LoginData ld = new LoginData();
ld.Deserialise(ref span, netMessage.dataLength);
Debug.Log(" [Main Update] LogindData= " + ld.ToString());
}
}
}
/*
// Can be used to send a simple opcode
// that is read with
// short opcode = Marshal.ReadInt16(netEvent.Packet.Data);
//
// Note that you can send a payload but you need to shift the data
// on the receiving side
private void SendPacket(Peer peer)
{
Packet packet = default(Packet);
short opcode = 7;
// To read on receiving side use:
data[0] = (byte)(opcode & 0x00FF);
data[1] = (byte)((opcode & 0xFF00) >> 8);
packet.Create(data, data.Length, PacketFlags.Reliable);
peer.Send(0, ref packet);
}
*/
private int SendPacketWithSpan(Peer peer, string username, int passHash)
{
Packet packet = default(Packet);
LoginData ld = new LoginData
{
passHash = passHash,
username = username
};
Span<byte> span = new Span<byte>(data);
ld.Serialise(ref span);
data = span.ToArray();
packet.Create(data, Marshal.SizeOf(ld), PacketFlags.Reliable);
peer.Send(0, ref packet);
return span.Length;
}
private void Server()
{
using (Host server = new Host())
{
Address address = new Address();
if (address.SetHost("0.0.0.0"))
Debug.Log("OK!");
address.Port = port;
server.Create(address, maxClients);
Event netEvent;
while (isAlive)
{
server.Service(0, out netEvent);
switch (netEvent.Type)
{
case EventType.None:
break;
case EventType.Connect:
Debug.Log("[Server] Client connected - ID: " + netEvent.Peer.ID + ", IP: " + netEvent.Peer.IP);
break;
case EventType.Disconnect:
Debug.Log("[Server] Client disconnected - ID: " + netEvent.Peer.ID + ", IP: " + netEvent.Peer.IP);
break;
case EventType.Timeout:
Debug.Log("[Server] Client timeout - ID: " + netEvent.Peer.ID + ", IP: " + netEvent.Peer.IP);
break;
case EventType.Receive:
Debug.Log("[Server] Packet received from - ID: " + netEvent.Peer.ID + ", IP: " + netEvent.Peer.IP + ", Channel ID: " + netEvent.ChannelID + ", Data length: " + netEvent.Packet.Length);
// ---------------- Test -------------------------
/*
// Example of sending a single opcode without span
short opcode = Marshal.ReadInt16(netEvent.Packet.Data); // <--- Only to make comparison to a 'non-span' method.
if (opcode == 7)
{
Debug.Log("----------- SendPacket message --------");
SendPacket(netEvent.Peer);
Debug.Log(" [Server] Packet sent to - ID: " + netEvent.Peer.ID + ", IP: " + netEvent.Peer.IP + ", Data length: " + data.Length);
}
*/
ReadOnlySpan<byte> span;
unsafe
{
// we could only read 2 bytes (aka a short) but we reuse the same span later
span = new ReadOnlySpan<byte>((byte*)netEvent.Packet.Data, netEvent.Packet.Length);
}
// Use NetData to get the opcode - note that you could add other values to NetData
// NetData netData = default;
// netData.Deserialise(ref span, 2);
// opcode = netData.opcode;
//Debug.Log("Received opcode= " + netData.opcode);
// Get opcode direcly
bitBuffer = BufferPool.GetBitBuffer();
bitBuffer.Clear();
bitBuffer.FromSpan(ref span, 2);
short opcode = bitBuffer.ReadShort();
if (opcode == 4)
{
//Debug.Log("----------- Span LoginData message --------");
//LoginData ld = new LoginData();
//ld.Deserialise(ref span, netEvent.Packet.Length);
//Debug.Log(" [Server] LogindData= " + ld.ToString());
NetMessage netMsg = new NetMessage
{
opcode = opcode,
peer = netEvent.Peer,
dataLength = netEvent.Packet.Length,
data = netEvent.Packet.Data
};
netMessageQueue.Enqueue(netMsg);
}
// -----------------------------------------------------------------
netEvent.Packet.Dispose();
Debug.Log("Packet disposed");
server.Flush();
break;
}
}
server.Flush();
}
}
private void Client()
{
using (Host client = new Host())
{
Address address = new Address();
address.SetHost("127.0.0.1");
address.Port = port;
client.Create();
Peer peer = client.Connect(address);
Event netEvent;
while (isAlive)
{
client.Service(15, out netEvent);
switch (netEvent.Type)
{
case EventType.None:
break;
case EventType.Connect:
Debug.Log("[Client] Client connected to server - ID: " + peer.ID);
// --------------- Sending Data Test ------------------
//SendPacket(peer);
//Debug.Log("[Client] Packet sent to server - Data length: " + data.Length);
int length = 0;
//length = SendPacketWithBitBuffer(peer);
Debug.Log("[Client] BitBuffer Packet sent to server - Data length: " + length);
length = SendPacketWithSpan(peer, "Name1", 51);
Debug.Log("[Client] Span Packet sent to server - Data length: " + length);
SendPacketWithSpan(peer, "Name2", 52);
SendPacketWithSpan(peer, "Name3", 53);
SendPacketWithSpan(peer, "Name4", 65);
// -----------------------------------------------------
break;
case EventType.Disconnect:
Debug.Log("[Client] Client disconnected from server");
break;
case EventType.Timeout:
Debug.Log("[Client] Client connection timeout");
break;
case EventType.Receive:
Debug.Log("[Client] Packet received from server - Channel ID: " + netEvent.ChannelID + ", Data length: " + netEvent.Packet.Length);
netEvent.Packet.Dispose(); // TODO should this be called AFTER it the data has been used on the other side?
peer.Disconnect(0);
break;
}
}
client.Flush();
}
}
private void OnDestroy() {
isAlive = false;
ENet.Library.Deinitialize();
}
}
static class BufferPool
{
[ThreadStatic]
private static BitBuffer bitBuffer;
public static BitBuffer GetBitBuffer() {
if (bitBuffer == null)
bitBuffer = new BitBuffer(1024);
return bitBuffer;
}
}
public struct NetData
{
public short opcode;
public void Serialise(ref Span<byte> packet)
{
BitBuffer data = BufferPool.GetBitBuffer();
data.Clear();
data.AddShort(opcode)
.ToSpan(ref packet);
}
public void Deserialise(ref ReadOnlySpan<byte> packet, int length)
{
BitBuffer data = BufferPool.GetBitBuffer();
data.Clear();
data.FromSpan(ref packet, length);
opcode = data.ReadShort();
}
}
public struct LoginData
{
public const short opcode = 4;
public int passHash;
public string username; // string
public override string ToString()
{
return "OpCode= " + opcode + " passHash= " + passHash
+ " username= " + username;
}
void Username(string userName)
{
username = userName;
}
// Can be used to send with bitbuffer and without span
//public void Serialise(BitBuffer buffer)
//{
// buffer.AddShort(opcode);
// buffer.AddInt(passHash);
//}
//
//public void Deserialise(BitBuffer buffer)
//{
// buffer.ReadShort();
// passHash = buffer.ReadInt();
//}
public void Serialise(ref Span<byte> packet)
{
BitBuffer data = BufferPool.GetBitBuffer();
data.Clear();
data.AddShort(opcode)
.AddInt(passHash)
.AddString(username)
.ToSpan(ref packet);
}
public void Deserialise(ref ReadOnlySpan<byte> packet, int length)
{
BitBuffer data = BufferPool.GetBitBuffer();
data.Clear();
data.FromSpan(ref packet, length);
data.ReadShort();
passHash = data.ReadInt();
username = data.ReadString();
}
}
public struct NetMessage
{
public short opcode;
public Peer peer;
public int dataLength;
public IntPtr data;
public bool IsSet() {
return opcode != 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment