Files
Simulator/DroneClient/TelemetryServer.cs

259 lines
8.4 KiB
C#

using DroneClient.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TelemetryIO;
using TelemetryIO.Models;
namespace TelemetryIO
{
internal class TelemetryServer : TelemetryIO.BaseCommHandler
{
ConcurrentQueue<byte[]> sendQueue = new ConcurrentQueue<byte[]>();
Telemetry telemetry = Telemetry.Instance;
MonitorContainer monitoring = MonitorContainer.Instance;
private bool isClientConnected = false;
public event EventHandler OnTeleClientConnected = delegate { };
public event EventHandler OnTeleClientDisconnected = delegate { };
public bool isClientAvailable { get { return isClientConnected; } }
public TelemetryServer()
{
}
public override void Close()
{
throw new NotImplementedException();
}
public override void CloseConnection()
{
throw new NotImplementedException();
}
public override bool IsOpen()
{
return true;
}
public async override Task Open()
{
await StartServerAsync();
//Console.ReadLine();
}
public async Task StartServerAsync()
{
var listener = new TcpListener(IPAddress.Any, Port);
listener.Start();
Console.WriteLine("Server is running");
try
{
while (true)
{
//if (isClientConnected) await Task.Delay(25);
var client = await listener.AcceptTcpClientAsync();
StrikeOnTeleClientConnected();
isClientConnected = true;
Debug.WriteLine("Client is connected");
//this.client = client;
var readTask = StartReadingAsync(client);
var writeTask = SendMessageAsync(client);
await readTask;
await writeTask;
}
}
catch (IOException ex) when (IsNetworkError(ex))
{
// Специальная обработка сетевых ошибок
Debug.WriteLine($"Ошибка при запуске сервера: {ex.Message}");
}
catch (Exception ex)
{
Debug.WriteLine("An error occurred: " + ex.Message);
}
finally
{
listener.Stop();
}
}
public async Task SendMessageAsync(TcpClient c)
{
if (c.GetStream() == null || !c.Connected)
{
Console.WriteLine("Not connected to server");
return;
}
while (c.Connected)
{
if (sendQueue.TryDequeue(out byte[] buffer))
{
try
{
await c.GetStream().WriteAsync(buffer, 0, buffer.Length);
Debug.WriteLine($"Sent");
}
catch (IOException ex) when (IsNetworkError(ex))
{
// Специальная обработка сетевых ошибок
Debug.WriteLine($"Клиент отключился: {ex.Message}");
HandleDisconnectedClient(c);
}
catch (Exception ex)
{
Debug.WriteLine($"Error sending message: {ex.Message}");
}
}
}
}
public async override Task StartReadingAsync(object C)
{
TcpClient client;
if (C is TcpClient) client = (TcpClient)C;
else
{
return;
}
try
{
using NetworkStream stream = client.GetStream();
while (client.Connected)
{
byte[] buffer = new byte[1024];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
//string response = await reader.ReadLineAsync();
if (bytesRead > 0)
{
EnqueueData(buffer, bytesRead);
}
data_extract();
}
}
catch (IOException ex) when (IsNetworkError(ex))
{
// Специальная обработка сетевых ошибок
Debug.WriteLine($"Клиент отключился: {ex.Message}");
HandleDisconnectedClient(client);
}
catch (Exception ex)
{
Debug.WriteLine($"Error sending message: {ex.Message}");
}
}
protected override void ProcessCommand(int cmd, int slot, byte[] data, int offset, int len)
{
Debug.WriteLine(@"server cmd = " + cmd);
switch (cmd)
{
case TELE_CMD_HELLO:
byte[] load = telemetry.getSlot(cmd, offset, len);
putRequest(prepareTelegram(cmd, 0, load, 0, load.Length));
break;
case TELE_CMD_RD_ONCE:
byte[] load1 = telemetry.getSlot(slot, offset, len);
putRequest(prepareTelegram(cmd, slot, load1, offset, load1.Length));
break;
case TELE_CMD_WR:
setData(data, slot, offset, len);
sendVoidAnswer(TELE_CMD_WR);
break;
case TELE_CMD_RD_MON_ON:
monitoring.isMonitor = 1;
sendVoidAnswer(TELE_CMD_RD_MON_ON);
break;
case TELE_CMD_RD_MON_OFF:
monitoring.isMonitor = 0;
sendVoidAnswer(TELE_CMD_RD_MON_OFF);
break;
case TELE_CMD_RD_MON_ADD:
int id = monitoring.monitorPut(slot, offset, 4);
sendIntAnswer(TELE_CMD_RD_MON_ADD, id);
monitoring.isMonitor = 1;
break;
case TELE_CMD_RD_MON_REMOVE:
id = monitoring.monitorRemove(offset);//in this case offset == id
if(monitoring.monitorFillLevel == 0)monitoring.isMonitor = 0;//if monitor_fill_level == 0 there is no item to monitor
if (monitoring.isMonitor > 0) sendIntAnswer(TELE_CMD_RD_MON_REMOVE, id);
else sendVoidAnswer(TELE_CMD_RD_MON_REMOVEALL);
break;
}
}
private void setData(byte[] load, int slot, int offset, int len)
{
telemetry.setSlot(slot, load, offset, len);
}
private void sendVoidAnswer(int command)
{
putRequest(prepareTelegram(command, 0, new byte[0], 0));
}
private void sendIntAnswer(int command, int param)
{
putRequest(prepareTelegram(command, 0, new byte[0], param));
}
protected override void sendData(byte[] data)
{
sendQueue.Enqueue(data);
}
public override void setCommParams(iCommParams commParams)
{
if (commParams.GetType() == typeof(TCPCommParams))
{
var comm = (TCPCommParams)commParams;
IP = comm.IP;
Port = comm.Port;
}
}
private void HandleDisconnectedClient(TcpClient client)
{
isClientConnected = false;
StrikeOnTeleClientDisconnected();
}
private bool IsNetworkError(Exception ex)
{
// Проверяем типичные сетевые ошибки при разрыве соединения
return ex is IOException
|| ex is SocketException
|| ex.InnerException is SocketException;
}
public void StrikeOnTeleClientConnected()
{
OnTeleClientConnected?.Invoke(this, EventArgs.Empty);
}
public void StrikeOnTeleClientDisconnected()
{
OnTeleClientDisconnected?.Invoke(this, EventArgs.Empty);
}
}
}