Skip to content

Instantly share code, notes, and snippets.

@RevenantX
Last active March 1, 2023 11:53
Show Gist options
  • Save RevenantX/e251b28a62d7c8caa570d352cd007c90 to your computer and use it in GitHub Desktop.
Save RevenantX/e251b28a62d7c8caa570d352cd007c90 to your computer and use it in GitHub Desktop.
using System;
using System.Net;
using System.Net.Sockets;
using LiteNetLib.Utils;
namespace Code.ExperimentalCode
{
public class UdpNetWrapper
{
class ClientData
{
private const int ReceiveBufferSize = 1500;
private readonly Socket _tcpSocket;
private readonly Socket _udpSocket;
private readonly byte[] _tcpBuffer = new byte[ReceiveBufferSize * 2];
private readonly byte[] _udpBuffer = new byte[ReceiveBufferSize];
private int _bufferPos;
private EndPoint _udpEp;
private readonly IPEndPoint _serverEndPoint;
public ClientData(Socket tcpSocket, IPEndPoint udpBindPoint, int targetPort, IPEndPoint serverEndPoint)
{
_serverEndPoint = serverEndPoint;
_tcpSocket = tcpSocket;
_udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
{
ReceiveBufferSize = BuffSize,
SendBufferSize = BuffSize
};
_udpSocket.Bind(udpBindPoint);
if (targetPort != 0) //server
{
_udpEp = new IPEndPoint(IPAddress.Loopback, targetPort);
_tcpSocket.BeginReceive(_tcpBuffer, 0, _tcpBuffer.Length, SocketFlags.None, AsyncTcpReceive, this);
}
else //client
{
_udpEp = new IPEndPoint(IPAddress.Loopback, 0);
}
_udpSocket.BeginReceiveFrom(_udpBuffer, 2, _udpBuffer.Length - 2, SocketFlags.None, ref _udpEp, AsyncUdpReceive, this);
}
private void AsyncTcpReceive(IAsyncResult asyncResult)
{
try
{
int size = _tcpSocket.EndReceive(asyncResult);
if (size == 0)
{
Close();
return;
}
_bufferPos += size;
while (_bufferPos > 2)
{
int packetSize = BitConverter.ToUInt16(_tcpBuffer, 0);
int totalSize = packetSize + 2;
if (_bufferPos < totalSize)
break;
_udpSocket.SendTo(_tcpBuffer, 2, packetSize, SocketFlags.None, _udpEp);
if(_bufferPos > totalSize)
Buffer.BlockCopy(_tcpBuffer, totalSize, _tcpBuffer, 0, _bufferPos - totalSize);
_bufferPos -= totalSize;
}
_tcpSocket.BeginReceive(_tcpBuffer, _bufferPos, _tcpBuffer.Length - _bufferPos, SocketFlags.None, AsyncTcpReceive, this);
}
catch (ObjectDisposedException)
{
Close();
}
catch
{
// Debug.Log(e.ToString());
Close();
}
}
private void AsyncUdpReceive(IAsyncResult asyncResult)
{
try
{
int size = _udpSocket.EndReceiveFrom(asyncResult, ref _udpEp);
if (!_tcpSocket.Connected)
{
_tcpSocket.Connect(_serverEndPoint);
_tcpSocket.BeginReceive(_tcpBuffer, 0, _tcpBuffer.Length, SocketFlags.None, AsyncTcpReceive, this);
}
FastBitConverter.GetBytes(_udpBuffer, 0, (ushort)size);
// _tcpSocket.Send(_udpBuffer, 0, size+2, SocketFlags.None);
var _tmp = new byte[ReceiveBufferSize * 2];
_udpBuffer.CopyTo(_tmp, 0);
_tcpSocket.BeginSend(_tmp, 0, size+2, SocketFlags.None, ar => { }, null);
//Console.WriteLine($"AsyncUdpReceive: {size}, ep: {_udpEp}, SendTo: {cd.TcpSocket.RemoteEndPoint}");
_udpSocket.BeginReceiveFrom(_udpBuffer, 2, _udpBuffer.Length - 2, SocketFlags.None, ref _udpEp, AsyncUdpReceive, this);
}
catch (ObjectDisposedException)
{
Close();
}
catch
{
// Debug.Log(e.ToString());
}
}
public void Close()
{
_tcpSocket.Close();
_udpSocket.Close();
}
}
private readonly Socket _tcpSocket;
private const int BuffSize = 1024 * 1024;
private readonly int _targetPort;
//Client mode
public UdpNetWrapper(int listenPort, IPEndPoint serverEndPoint)
{
_tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
ReceiveBufferSize = BuffSize,
SendBufferSize = BuffSize
};
//_tcpSocket.Bind(new IPEndPoint(IPAddress.Any, 0));
new ClientData(_tcpSocket, new IPEndPoint(IPAddress.Loopback, listenPort), 0, serverEndPoint);
}
//Server mode
public UdpNetWrapper(int listenPort, int targetPort)
{
_targetPort = targetPort;
_tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
ReceiveBufferSize = BuffSize,
SendBufferSize = BuffSize
};
_tcpSocket.Bind(new IPEndPoint(IPAddress.Any, listenPort));
_tcpSocket.Listen(1000);
_tcpSocket.BeginAccept(AsyncTcpAccept, _tcpSocket);
}
private void AsyncTcpAccept(IAsyncResult asyncResult)
{
ClientData cd = null;
try
{
Socket user = _tcpSocket.EndAccept(asyncResult);
cd = new ClientData(user, new IPEndPoint(IPAddress.Any, 0), _targetPort, null);
}
catch(Exception)
{
if (cd != null)
{
cd.Close();
}
}
try
{
_tcpSocket.BeginAccept(AsyncTcpAccept, _tcpSocket);
}
catch (Exception)
{
//nothing
}
}
public void Close()
{
_tcpSocket.Close();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment