-
-
Save MSylvia/718124045f377885efc34d69ca29ded8 to your computer and use it in GitHub Desktop.
Simple Test Case to Send messages with ENet-Sharp & ENetStack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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