hawkeye camera support(not tested)
This commit is contained in:
220
framework/Inspectron.HawkEye/UDPB/UDPBSocket.cs
Normal file
220
framework/Inspectron.HawkEye/UDPB/UDPBSocket.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace Inspectron.HawkEye.UDPB
|
||||
{
|
||||
public class UDPBSocket : IDisposable
|
||||
{
|
||||
public int LossSimulation { get; set; }
|
||||
|
||||
public EndPoint LastConnection => _lastConnection;
|
||||
private readonly UDPBQueue _queue;
|
||||
|
||||
private readonly UDPBReceiveBuffer _receiveBuffer;
|
||||
|
||||
private readonly byte[] _receivePacketBuffer = new byte[10 * 1024 * 1024];
|
||||
private readonly Random _rnd = new Random();
|
||||
private Socket _localSocket;
|
||||
private uint _currentSquenceId = 1;
|
||||
|
||||
private EndPoint _lastConnection = new IPEndPoint(IPAddress.Any, 27001);
|
||||
private bool _isServer;
|
||||
private readonly ConcurrentQueue<byte[]> _receiveQueue = new ConcurrentQueue<byte[]>();
|
||||
private bool _isReceiveing = true;
|
||||
private readonly Thread _receiveThread;
|
||||
private readonly List<UDPBPacket> _packetCache = new List<UDPBPacket>();
|
||||
|
||||
public UDPBSocket()
|
||||
{
|
||||
_queue = new UDPBQueue();
|
||||
_receiveBuffer = new UDPBReceiveBuffer(this, _receiveQueue);
|
||||
|
||||
_receiveThread = new Thread(ReceiveLoop);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_isServer) _localSocket.Disconnect(false);
|
||||
_isReceiveing = false;
|
||||
}
|
||||
|
||||
public static int FindFreePort(IPAddress adapter)
|
||||
{
|
||||
var port = 0;
|
||||
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
try
|
||||
{
|
||||
var localEP = new IPEndPoint(adapter, 0);
|
||||
socket.Bind(localEP);
|
||||
localEP = (IPEndPoint) socket.LocalEndPoint;
|
||||
port = localEP.Port;
|
||||
}
|
||||
finally
|
||||
{
|
||||
socket.Close();
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
public void Listen(IPAddress adapter, int port)
|
||||
{
|
||||
Console.WriteLine($"Listen on {adapter}");
|
||||
_isServer = true;
|
||||
_localSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
_localSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);
|
||||
//_localSocket.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.DontFragment, true);
|
||||
_localSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 10 * 1024 * 1024);
|
||||
_localSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, 10 * 1024 * 1024);
|
||||
|
||||
_localSocket.Bind(new IPEndPoint(adapter, port));
|
||||
_receiveThread.Start();
|
||||
}
|
||||
|
||||
public void Connect(IPEndPoint endpoint, IPAddress adapter)
|
||||
{
|
||||
Console.WriteLine($"Connect to {adapter}");
|
||||
_localSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
//_localSocket.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.DontFragment, true);
|
||||
_localSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 10 * 1024 * 1024);
|
||||
_localSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, 10 * 1024 * 1024);
|
||||
|
||||
Console.WriteLine($"Binding on {adapter?.MapToIPv4()}");
|
||||
|
||||
if (adapter != null)
|
||||
_localSocket.Bind(new IPEndPoint(adapter.MapToIPv4(), 0));
|
||||
_localSocket.Connect(endpoint);
|
||||
_receiveThread.Start();
|
||||
}
|
||||
|
||||
|
||||
public void SendData(byte[] data)
|
||||
{
|
||||
_packetCache.Clear();
|
||||
IncrementSequence();
|
||||
var begin = new UDPBPacket {Type = UDPBPacket.EPacketType.BeginSequence, SequenceId = _currentSquenceId};
|
||||
SendPacket(begin, true);
|
||||
|
||||
|
||||
_queue.Reset();
|
||||
_queue.AddBuffer(data, 0, data.Length);
|
||||
var lastId = Flush();
|
||||
|
||||
|
||||
var finish = new UDPBPacket
|
||||
{Type = UDPBPacket.EPacketType.CloseSequence, MessageId = lastId + 1, SequenceId = _currentSquenceId};
|
||||
SendPacket(finish, true);
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
byte[] dataOK;
|
||||
|
||||
dataOK = Receive();
|
||||
|
||||
|
||||
_localSocket.ReceiveTimeout = 0;
|
||||
|
||||
var packet = new UDPBPacket();
|
||||
packet.Deserialize(dataOK, 0, dataOK.Length);
|
||||
|
||||
if (packet.Type == UDPBPacket.EPacketType.Ok)
|
||||
{
|
||||
Console.WriteLine("OK");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet.Type == UDPBPacket.EPacketType.Nak)
|
||||
{
|
||||
var ms = new MemoryStream(packet.Payload);
|
||||
var br = new BinaryReader(ms);
|
||||
var packets = br.ReadInt32();
|
||||
Console.WriteLine("NAK " + packets);
|
||||
for (var i = 0; i < packets; i++)
|
||||
{
|
||||
var id = br.ReadUInt32();
|
||||
var p = _packetCache.First(x => x.MessageId == id);
|
||||
SendPacket(p, true);
|
||||
}
|
||||
|
||||
SendPacket(finish, true);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
public byte[] Receive()
|
||||
{
|
||||
byte[] res;
|
||||
while (!_receiveQueue.TryDequeue(out res)) Thread.Sleep(1);
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
internal void SendPacket(UDPBPacket packet, bool noCache = false)
|
||||
{
|
||||
if (!noCache) _packetCache.Add(packet);
|
||||
|
||||
if (LossSimulation > 0)
|
||||
if (_rnd.Next(LossSimulation) == LossSimulation - 1)
|
||||
return;
|
||||
|
||||
if (_isServer)
|
||||
_localSocket.SendTo(packet.Serialize(), _lastConnection);
|
||||
else
|
||||
_localSocket.Send(packet.Serialize());
|
||||
}
|
||||
|
||||
private void ReceiveLoop()
|
||||
{
|
||||
while (_isReceiveing)
|
||||
{
|
||||
var received = ReceiveFrom(_receivePacketBuffer, 0);
|
||||
_receiveBuffer.AddPacketBytes(_receivePacketBuffer, 0, received);
|
||||
}
|
||||
}
|
||||
|
||||
private int ReceiveFrom(byte[] buffer, int bufferOffset)
|
||||
{
|
||||
return _localSocket.ReceiveFrom(buffer, bufferOffset,
|
||||
UDPBQueue.PACKET_SIZE + UDPBPacket.packetHeaderSize,
|
||||
SocketFlags.None, ref _lastConnection);
|
||||
}
|
||||
|
||||
|
||||
private void IncrementSequence()
|
||||
{
|
||||
_currentSquenceId++;
|
||||
if (_currentSquenceId == uint.MaxValue) _currentSquenceId = 1;
|
||||
}
|
||||
|
||||
private uint Flush()
|
||||
{
|
||||
uint lastPacketId = 0;
|
||||
while (_queue.PacketsToSend() != 0)
|
||||
{
|
||||
var packet = new UDPBPacket();
|
||||
byte[] data = null;
|
||||
uint msgNo = 0;
|
||||
var payload = _queue.ReadData(ref data, ref msgNo);
|
||||
packet.Type = UDPBPacket.EPacketType.Data;
|
||||
packet.Length = payload;
|
||||
packet.Payload = data;
|
||||
packet.MessageId = msgNo;
|
||||
packet.SequenceId = _currentSquenceId;
|
||||
SendPacket(packet);
|
||||
lastPacketId = msgNo;
|
||||
}
|
||||
|
||||
return lastPacketId;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user