mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 11:00:32 +00:00
fix: kcp2k V1.12 (updated)
-> where-allocation now optional to handle platforms that don't support it
This commit is contained in:
parent
d66d228079
commit
6d021c0875
@ -34,8 +34,10 @@ public class KcpTransport : Transport
|
|||||||
public uint SendWindowSize = 4096; //Kcp.WND_SND; 32 by default. Mirror sends a lot, so we need a lot more.
|
public uint SendWindowSize = 4096; //Kcp.WND_SND; 32 by default. Mirror sends a lot, so we need a lot more.
|
||||||
[Tooltip("KCP window size can be modified to support higher loads.")]
|
[Tooltip("KCP window size can be modified to support higher loads.")]
|
||||||
public uint ReceiveWindowSize = 4096; //Kcp.WND_RCV; 128 by default. Mirror sends a lot, so we need a lot more.
|
public uint ReceiveWindowSize = 4096; //Kcp.WND_RCV; 128 by default. Mirror sends a lot, so we need a lot more.
|
||||||
|
[Tooltip("Enable to use where-allocation NonAlloc KcpServer/Client/Connection versions. Highly recommended on all Unity platforms.")]
|
||||||
|
public bool NonAlloc = true;
|
||||||
|
|
||||||
// server & client
|
// server & client (where-allocation NonAlloc versions)
|
||||||
KcpServer server;
|
KcpServer server;
|
||||||
KcpClient client;
|
KcpClient client;
|
||||||
|
|
||||||
@ -60,26 +62,42 @@ void Awake()
|
|||||||
Log.Error = Debug.LogError;
|
Log.Error = Debug.LogError;
|
||||||
|
|
||||||
// client
|
// client
|
||||||
client = new KcpClient(
|
client = NonAlloc
|
||||||
() => OnClientConnected.Invoke(),
|
? new KcpClientNonAlloc(
|
||||||
(message) => OnClientDataReceived.Invoke(message, Channels.Reliable),
|
() => OnClientConnected.Invoke(),
|
||||||
() => OnClientDisconnected.Invoke()
|
(message) => OnClientDataReceived.Invoke(message, Channels.Reliable),
|
||||||
);
|
() => OnClientDisconnected.Invoke())
|
||||||
|
: new KcpClient(
|
||||||
|
() => OnClientConnected.Invoke(),
|
||||||
|
(message) => OnClientDataReceived.Invoke(message, Channels.Reliable),
|
||||||
|
() => OnClientDisconnected.Invoke());
|
||||||
|
|
||||||
// server
|
// server
|
||||||
server = new KcpServer(
|
server = NonAlloc
|
||||||
(connectionId) => OnServerConnected.Invoke(connectionId),
|
? new KcpServerNonAlloc(
|
||||||
(connectionId, message) => OnServerDataReceived.Invoke(connectionId, message, Channels.Reliable),
|
(connectionId) => OnServerConnected.Invoke(connectionId),
|
||||||
(connectionId) => OnServerDisconnected.Invoke(connectionId),
|
(connectionId, message) => OnServerDataReceived.Invoke(connectionId, message, Channels.Reliable),
|
||||||
DualMode,
|
(connectionId) => OnServerDisconnected.Invoke(connectionId),
|
||||||
NoDelay,
|
DualMode,
|
||||||
Interval,
|
NoDelay,
|
||||||
FastResend,
|
Interval,
|
||||||
CongestionWindow,
|
FastResend,
|
||||||
SendWindowSize,
|
CongestionWindow,
|
||||||
ReceiveWindowSize,
|
SendWindowSize,
|
||||||
Timeout
|
ReceiveWindowSize,
|
||||||
);
|
Timeout)
|
||||||
|
: new KcpServer(
|
||||||
|
(connectionId) => OnServerConnected.Invoke(connectionId),
|
||||||
|
(connectionId, message) => OnServerDataReceived.Invoke(connectionId, message, Channels.Reliable),
|
||||||
|
(connectionId) => OnServerDisconnected.Invoke(connectionId),
|
||||||
|
DualMode,
|
||||||
|
NoDelay,
|
||||||
|
Interval,
|
||||||
|
FastResend,
|
||||||
|
CongestionWindow,
|
||||||
|
SendWindowSize,
|
||||||
|
ReceiveWindowSize,
|
||||||
|
Timeout);
|
||||||
|
|
||||||
if (statisticsLog)
|
if (statisticsLog)
|
||||||
InvokeRepeating(nameof(OnLogStatistics), 1, 1);
|
InvokeRepeating(nameof(OnLogStatistics), 1, 1);
|
||||||
|
@ -22,6 +22,11 @@ public KcpClient(Action OnConnected, Action<ArraySegment<byte>> OnData, Action O
|
|||||||
this.OnDisconnected = OnDisconnected;
|
this.OnDisconnected = OnDisconnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateConnection can be overwritten for where-allocation:
|
||||||
|
// https://github.com/vis2k/where-allocation
|
||||||
|
protected virtual KcpClientConnection CreateConnection() =>
|
||||||
|
new KcpClientConnection();
|
||||||
|
|
||||||
public void Connect(string address, ushort port, bool noDelay, uint interval, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV, int timeout = KcpConnection.DEFAULT_TIMEOUT)
|
public void Connect(string address, ushort port, bool noDelay, uint interval, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV, int timeout = KcpConnection.DEFAULT_TIMEOUT)
|
||||||
{
|
{
|
||||||
if (connected)
|
if (connected)
|
||||||
@ -30,7 +35,8 @@ public void Connect(string address, ushort port, bool noDelay, uint interval, in
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
connection = new KcpClientConnection();
|
// create connection
|
||||||
|
connection = CreateConnection();
|
||||||
|
|
||||||
// setup events
|
// setup events
|
||||||
connection.OnAuthenticated = () =>
|
connection.OnAuthenticated = () =>
|
||||||
|
@ -28,6 +28,15 @@ public static bool ResolveHostname(string hostname, out IPAddress[] addresses)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EndPoint & Receive functions can be overwritten for where-allocation:
|
||||||
|
// https://github.com/vis2k/where-allocation
|
||||||
|
// NOTE: Client's SendTo doesn't allocate, don't need a virtual.
|
||||||
|
protected virtual void CreateRemoteEndPoint(IPAddress[] addresses, ushort port) =>
|
||||||
|
remoteEndPoint = new IPEndPoint(addresses[0], port);
|
||||||
|
|
||||||
|
protected virtual int ReceiveFrom(byte[] buffer) =>
|
||||||
|
socket.ReceiveFrom(buffer, ref remoteEndPoint);
|
||||||
|
|
||||||
public void Connect(string host, ushort port, bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV, int timeout = DEFAULT_TIMEOUT)
|
public void Connect(string host, ushort port, bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV, int timeout = DEFAULT_TIMEOUT)
|
||||||
{
|
{
|
||||||
Log.Info($"KcpClient: connect to {host}:{port}");
|
Log.Info($"KcpClient: connect to {host}:{port}");
|
||||||
@ -35,9 +44,14 @@ public void Connect(string host, ushort port, bool noDelay, uint interval = Kcp.
|
|||||||
// try resolve host name
|
// try resolve host name
|
||||||
if (ResolveHostname(host, out IPAddress[] addresses))
|
if (ResolveHostname(host, out IPAddress[] addresses))
|
||||||
{
|
{
|
||||||
remoteEndpoint = new IPEndPoint(addresses[0], port);
|
// create remote endpoint
|
||||||
socket = new Socket(remoteEndpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
CreateRemoteEndPoint(addresses, port);
|
||||||
socket.Connect(remoteEndpoint);
|
|
||||||
|
// create socket
|
||||||
|
socket = new Socket(remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
||||||
|
socket.Connect(remoteEndPoint);
|
||||||
|
|
||||||
|
// set up kcp
|
||||||
SetupKcp(noDelay, interval, fastResend, congestionWindow, sendWindowSize, receiveWindowSize, timeout);
|
SetupKcp(noDelay, interval, fastResend, congestionWindow, sendWindowSize, receiveWindowSize, timeout);
|
||||||
|
|
||||||
// client should send handshake to server as very first message
|
// client should send handshake to server as very first message
|
||||||
@ -49,6 +63,7 @@ public void Connect(string host, ushort port, bool noDelay, uint interval = Kcp.
|
|||||||
else OnDisconnected();
|
else OnDisconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// call from transport update
|
// call from transport update
|
||||||
public void RawReceive()
|
public void RawReceive()
|
||||||
{
|
{
|
||||||
@ -58,7 +73,7 @@ public void RawReceive()
|
|||||||
{
|
{
|
||||||
while (socket.Poll(0, SelectMode.SelectRead))
|
while (socket.Poll(0, SelectMode.SelectRead))
|
||||||
{
|
{
|
||||||
int msgLength = socket.ReceiveFrom(rawReceiveBuffer, ref remoteEndpoint);
|
int msgLength = ReceiveFrom(rawReceiveBuffer);
|
||||||
// IMPORTANT: detect if buffer was too small for the
|
// IMPORTANT: detect if buffer was too small for the
|
||||||
// received msgLength. otherwise the excess
|
// received msgLength. otherwise the excess
|
||||||
// data would be silently lost.
|
// data would be silently lost.
|
||||||
|
@ -10,7 +10,7 @@ enum KcpState { Connected, Authenticated, Disconnected }
|
|||||||
public abstract class KcpConnection
|
public abstract class KcpConnection
|
||||||
{
|
{
|
||||||
protected Socket socket;
|
protected Socket socket;
|
||||||
protected EndPoint remoteEndpoint;
|
protected EndPoint remoteEndPoint;
|
||||||
internal Kcp kcp;
|
internal Kcp kcp;
|
||||||
|
|
||||||
// kcp can have several different states, let's use a state machine
|
// kcp can have several different states, let's use a state machine
|
||||||
@ -650,7 +650,7 @@ public void Disconnect()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get remote endpoint
|
// get remote endpoint
|
||||||
public EndPoint GetRemoteEndPoint() => remoteEndpoint;
|
public EndPoint GetRemoteEndPoint() => remoteEndPoint;
|
||||||
|
|
||||||
// pause/unpause to safely support mirror scene handling and to
|
// pause/unpause to safely support mirror scene handling and to
|
||||||
// immediately pause the receive while loop if needed.
|
// immediately pause the receive while loop if needed.
|
||||||
|
@ -43,7 +43,7 @@ public class KcpServer
|
|||||||
public int Timeout;
|
public int Timeout;
|
||||||
|
|
||||||
// state
|
// state
|
||||||
Socket socket;
|
protected Socket socket;
|
||||||
EndPoint newClientEP;
|
EndPoint newClientEP;
|
||||||
|
|
||||||
// IMPORTANT: raw receive buffer always needs to be of 'MTU' size, even
|
// IMPORTANT: raw receive buffer always needs to be of 'MTU' size, even
|
||||||
@ -137,6 +137,33 @@ public string GetClientAddress(int connectionId)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EndPoint & Receive functions can be overwritten for where-allocation:
|
||||||
|
// https://github.com/vis2k/where-allocation
|
||||||
|
protected virtual int ReceiveFrom(byte[] buffer, out int connectionHash)
|
||||||
|
{
|
||||||
|
// NOTE: ReceiveFrom allocates.
|
||||||
|
// we pass our IPEndPoint to ReceiveFrom.
|
||||||
|
// receive from calls newClientEP.Create(socketAddr).
|
||||||
|
// IPEndPoint.Create always returns a new IPEndPoint.
|
||||||
|
// https://github.com/mono/mono/blob/f74eed4b09790a0929889ad7fc2cf96c9b6e3757/mcs/class/System/System.Net.Sockets/Socket.cs#L1761
|
||||||
|
int read = socket.ReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP);
|
||||||
|
|
||||||
|
// calculate connectionHash from endpoint
|
||||||
|
// NOTE: IPEndPoint.GetHashCode() allocates.
|
||||||
|
// it calls m_Address.GetHashCode().
|
||||||
|
// m_Address is an IPAddress.
|
||||||
|
// GetHashCode() allocates for IPv6:
|
||||||
|
// https://github.com/mono/mono/blob/bdd772531d379b4e78593587d15113c37edd4a64/mcs/class/referencesource/System/net/System/Net/IPAddress.cs#L699
|
||||||
|
//
|
||||||
|
// => using only newClientEP.Port wouldn't work, because
|
||||||
|
// different connections can have the same port.
|
||||||
|
connectionHash = newClientEP.GetHashCode();
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual KcpServerConnection CreateConnection() =>
|
||||||
|
new KcpServerConnection(socket, newClientEP, NoDelay, Interval, FastResend, CongestionWindow, SendWindowSize, ReceiveWindowSize, Timeout);
|
||||||
|
|
||||||
// process incoming messages. should be called before updating the world.
|
// process incoming messages. should be called before updating the world.
|
||||||
HashSet<int> connectionsToRemove = new HashSet<int>();
|
HashSet<int> connectionsToRemove = new HashSet<int>();
|
||||||
public void TickIncoming()
|
public void TickIncoming()
|
||||||
@ -145,25 +172,10 @@ public void TickIncoming()
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// NOTE: ReceiveFrom allocates.
|
// receive
|
||||||
// we pass our IPEndPoint to ReceiveFrom.
|
int msgLength = ReceiveFrom(rawReceiveBuffer, out int connectionId);
|
||||||
// receive from calls newClientEP.Create(socketAddr).
|
|
||||||
// IPEndPoint.Create always returns a new IPEndPoint.
|
|
||||||
// https://github.com/mono/mono/blob/f74eed4b09790a0929889ad7fc2cf96c9b6e3757/mcs/class/System/System.Net.Sockets/Socket.cs#L1761
|
|
||||||
int msgLength = socket.ReceiveFrom(rawReceiveBuffer, 0, rawReceiveBuffer.Length, SocketFlags.None, ref newClientEP);
|
|
||||||
//Log.Info($"KCP: server raw recv {msgLength} bytes = {BitConverter.ToString(buffer, 0, msgLength)}");
|
//Log.Info($"KCP: server raw recv {msgLength} bytes = {BitConverter.ToString(buffer, 0, msgLength)}");
|
||||||
|
|
||||||
// calculate connectionId from endpoint
|
|
||||||
// NOTE: IPEndPoint.GetHashCode() allocates.
|
|
||||||
// it calls m_Address.GetHashCode().
|
|
||||||
// m_Address is an IPAddress.
|
|
||||||
// GetHashCode() allocates for IPv6:
|
|
||||||
// https://github.com/mono/mono/blob/bdd772531d379b4e78593587d15113c37edd4a64/mcs/class/referencesource/System/net/System/Net/IPAddress.cs#L699
|
|
||||||
//
|
|
||||||
// => using only newClientEP.Port wouldn't work, because
|
|
||||||
// different connections can have the same port.
|
|
||||||
int connectionId = newClientEP.GetHashCode();
|
|
||||||
|
|
||||||
// IMPORTANT: detect if buffer was too small for the received
|
// IMPORTANT: detect if buffer was too small for the received
|
||||||
// msgLength. otherwise the excess data would be
|
// msgLength. otherwise the excess data would be
|
||||||
// silently lost.
|
// silently lost.
|
||||||
@ -173,8 +185,9 @@ public void TickIncoming()
|
|||||||
// is this a new connection?
|
// is this a new connection?
|
||||||
if (!connections.TryGetValue(connectionId, out KcpServerConnection connection))
|
if (!connections.TryGetValue(connectionId, out KcpServerConnection connection))
|
||||||
{
|
{
|
||||||
// create a new KcpConnection
|
// create a new KcpConnection based on last received
|
||||||
connection = new KcpServerConnection(socket, newClientEP, NoDelay, Interval, FastResend, CongestionWindow, SendWindowSize, ReceiveWindowSize, Timeout);
|
// EndPoint. can be overwritten for where-allocation.
|
||||||
|
connection = CreateConnection();
|
||||||
|
|
||||||
// DO NOT add to connections yet. only if the first message
|
// DO NOT add to connections yet. only if the first message
|
||||||
// is actually the kcp handshake. otherwise it's either:
|
// is actually the kcp handshake. otherwise it's either:
|
||||||
@ -205,7 +218,7 @@ public void TickIncoming()
|
|||||||
|
|
||||||
// add to connections dict after being authenticated.
|
// add to connections dict after being authenticated.
|
||||||
connections.Add(connectionId, connection);
|
connections.Add(connectionId, connection);
|
||||||
Log.Info($"KCP: server added connection({connectionId}): {newClientEP}");
|
Log.Info($"KCP: server added connection({connectionId})");
|
||||||
|
|
||||||
// setup Data + Disconnected events only AFTER the
|
// setup Data + Disconnected events only AFTER the
|
||||||
// handshake. we don't want to fire OnServerDisconnected
|
// handshake. we don't want to fire OnServerDisconnected
|
||||||
|
@ -5,16 +5,18 @@ namespace kcp2k
|
|||||||
{
|
{
|
||||||
public class KcpServerConnection : KcpConnection
|
public class KcpServerConnection : KcpConnection
|
||||||
{
|
{
|
||||||
public KcpServerConnection(Socket socket, EndPoint remoteEndpoint, bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV, int timeout = DEFAULT_TIMEOUT)
|
// Constructor & Send functions can be overwritten for where-allocation:
|
||||||
|
// https://github.com/vis2k/where-allocation
|
||||||
|
public KcpServerConnection(Socket socket, EndPoint remoteEndPoint, bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV, int timeout = DEFAULT_TIMEOUT)
|
||||||
{
|
{
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
this.remoteEndpoint = remoteEndpoint;
|
this.remoteEndPoint = remoteEndPoint;
|
||||||
SetupKcp(noDelay, interval, fastResend, congestionWindow, sendWindowSize, receiveWindowSize, timeout);
|
SetupKcp(noDelay, interval, fastResend, congestionWindow, sendWindowSize, receiveWindowSize, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void RawSend(byte[] data, int length)
|
protected override void RawSend(byte[] data, int length)
|
||||||
{
|
{
|
||||||
socket.SendTo(data, 0, length, SocketFlags.None, remoteEndpoint);
|
socket.SendTo(data, 0, length, SocketFlags.None, remoteEndPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0b320ff06046474eae7bce7240ea478c
|
||||||
|
timeCreated: 1626430641
|
@ -0,0 +1,24 @@
|
|||||||
|
// where-allocation version of KcpClientConnection.
|
||||||
|
// may not be wanted on all platforms, so it's an extra optional class.
|
||||||
|
using System.Net;
|
||||||
|
using WhereAllocation;
|
||||||
|
|
||||||
|
namespace kcp2k
|
||||||
|
{
|
||||||
|
public class KcpClientConnectionNonAlloc : KcpClientConnection
|
||||||
|
{
|
||||||
|
IPEndPointNonAlloc reusableEP;
|
||||||
|
|
||||||
|
protected override void CreateRemoteEndPoint(IPAddress[] addresses, ushort port)
|
||||||
|
{
|
||||||
|
// create reusableEP with same address family as remoteEndPoint.
|
||||||
|
// otherwise ReceiveFrom_NonAlloc couldn't use it.
|
||||||
|
reusableEP = new IPEndPointNonAlloc(addresses[0], port);
|
||||||
|
base.CreateRemoteEndPoint(addresses, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
// where-allocation nonalloc recv
|
||||||
|
protected override int ReceiveFrom(byte[] buffer) =>
|
||||||
|
socket.ReceiveFrom_NonAlloc(buffer, reusableEP);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4c1b235bbe054706bef6d092f361006e
|
||||||
|
timeCreated: 1626430539
|
@ -0,0 +1,17 @@
|
|||||||
|
// where-allocation version of KcpClientConnectionNonAlloc.
|
||||||
|
// may not be wanted on all platforms, so it's an extra optional class.
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace kcp2k
|
||||||
|
{
|
||||||
|
public class KcpClientNonAlloc : KcpClient
|
||||||
|
{
|
||||||
|
public KcpClientNonAlloc(Action OnConnected, Action<ArraySegment<byte>> OnData, Action OnDisconnected)
|
||||||
|
: base(OnConnected, OnData, OnDisconnected)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override KcpClientConnection CreateConnection() =>
|
||||||
|
new KcpClientConnectionNonAlloc();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2cf0ccf7d551480bb5af08fcbe169f84
|
||||||
|
timeCreated: 1626435264
|
@ -0,0 +1,25 @@
|
|||||||
|
// where-allocation version of KcpServerConnection.
|
||||||
|
// may not be wanted on all platforms, so it's an extra optional class.
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using WhereAllocation;
|
||||||
|
|
||||||
|
namespace kcp2k
|
||||||
|
{
|
||||||
|
public class KcpServerConnectionNonAlloc : KcpServerConnection
|
||||||
|
{
|
||||||
|
IPEndPointNonAlloc reusableSendEndPoint;
|
||||||
|
|
||||||
|
public KcpServerConnectionNonAlloc(Socket socket, EndPoint remoteEndpoint, IPEndPointNonAlloc reusableSendEndPoint, bool noDelay, uint interval = Kcp.INTERVAL, int fastResend = 0, bool congestionWindow = true, uint sendWindowSize = Kcp.WND_SND, uint receiveWindowSize = Kcp.WND_RCV, int timeout = DEFAULT_TIMEOUT)
|
||||||
|
: base(socket, remoteEndpoint, noDelay, interval, fastResend, congestionWindow, sendWindowSize, receiveWindowSize, timeout)
|
||||||
|
{
|
||||||
|
this.reusableSendEndPoint = reusableSendEndPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RawSend(byte[] data, int length)
|
||||||
|
{
|
||||||
|
// where-allocation nonalloc send
|
||||||
|
socket.SendTo_NonAlloc(data, 0, length, SocketFlags.None, reusableSendEndPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4e1b74cc224b4c83a0f6c8d8da9090ab
|
||||||
|
timeCreated: 1626430608
|
@ -0,0 +1,51 @@
|
|||||||
|
// where-allocation version of KcpServer.
|
||||||
|
// may not be wanted on all platforms, so it's an extra optional class.
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using WhereAllocation;
|
||||||
|
|
||||||
|
namespace kcp2k
|
||||||
|
{
|
||||||
|
public class KcpServerNonAlloc : KcpServer
|
||||||
|
{
|
||||||
|
IPEndPointNonAlloc reusableClientEP;
|
||||||
|
|
||||||
|
public KcpServerNonAlloc(Action<int> OnConnected, Action<int, ArraySegment<byte>> OnData, Action<int> OnDisconnected, bool DualMode, bool NoDelay, uint Interval, int FastResend = 0, bool CongestionWindow = true, uint SendWindowSize = Kcp.WND_SND, uint ReceiveWindowSize = Kcp.WND_RCV, int Timeout = KcpConnection.DEFAULT_TIMEOUT)
|
||||||
|
: base(OnConnected, OnData, OnDisconnected, DualMode, NoDelay, Interval, FastResend, CongestionWindow, SendWindowSize, ReceiveWindowSize, Timeout)
|
||||||
|
{
|
||||||
|
// create reusableClientEP either IPv4 or IPv6
|
||||||
|
reusableClientEP = DualMode
|
||||||
|
? new IPEndPointNonAlloc(IPAddress.IPv6Any, 0)
|
||||||
|
: new IPEndPointNonAlloc(IPAddress.Any, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int ReceiveFrom(byte[] buffer, out int connectionHash)
|
||||||
|
{
|
||||||
|
// where-allocation nonalloc ReceiveFrom.
|
||||||
|
int read = socket.ReceiveFrom_NonAlloc(buffer, 0, buffer.Length, SocketFlags.None, reusableClientEP);
|
||||||
|
SocketAddress remoteAddress = reusableClientEP.temp;
|
||||||
|
|
||||||
|
// where-allocation nonalloc GetHashCode
|
||||||
|
connectionHash = remoteAddress.GetHashCode();
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override KcpServerConnection CreateConnection()
|
||||||
|
{
|
||||||
|
// IPEndPointNonAlloc is reused all the time.
|
||||||
|
// we can't store that as the connection's endpoint.
|
||||||
|
// we need a new copy!
|
||||||
|
IPEndPoint newClientEP = reusableClientEP.DeepCopyIPEndPoint();
|
||||||
|
|
||||||
|
// for allocation free sending, we also need another
|
||||||
|
// IPEndPointNonAlloc...
|
||||||
|
IPEndPointNonAlloc reusableSendEP = new IPEndPointNonAlloc(newClientEP.Address, newClientEP.Port);
|
||||||
|
|
||||||
|
// create a new KcpConnection NonAlloc version
|
||||||
|
// -> where-allocation IPEndPointNonAlloc is reused.
|
||||||
|
// need to create a new one from the temp address.
|
||||||
|
return new KcpServerConnectionNonAlloc(socket, newClientEP, reusableSendEP, NoDelay, Interval, FastResend, CongestionWindow, SendWindowSize, ReceiveWindowSize, Timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 54b8398dcd544c8a93bcad846214cc40
|
||||||
|
timeCreated: 1626432191
|
Loading…
Reference in New Issue
Block a user