Если вы хотите, чтобы клиенты не могли отправлять что-либо в течение периода ожидания, вам понадобится какой-то способ, чтобы они знали, что сервер не находится в состоянии прослушивания.Вы можете запустить отдельную задачу на другом порту, который клиенты могут запросить, чтобы узнать, можно ли передавать и обрабатывать данные на главном порту.Есть много способов сделать это, но основная идея проста, как кажется: клиент запрашивает вторичный порт, сервер отвечает сообщением, указывающим, является ли первичный порт «подключенным».Если нет, клиент ждет, пока он не получит разрешение от сервера.Если это так, клиент может немедленно отправить свою информацию через.
Если это не звучит привлекательно, вы также можете реализовать модель очереди данных на стороне сервера.Одна задача может заполнить BlockingCollection входящими данными от клиентов и другой поток для обработки данных, извлеченных из этого источника.Обратите внимание, что это не остановит передачу, поэтому это не идеальное решение вашей проблемы, но оно имеет ряд преимуществ.Вот (некорректный) пример того, как может выглядеть код:
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace ExampleNamespace
{
/*
* data class; encapsulates byte array data received from a client.
* in an actual implementation this might be a nice spot to put code
* that interprets bytes from the client in some way
*/
public class Transmission
{
public IPEndPoint Client { get; set; }
public byte[] Data { get; set; }
public Transmission(IPEndPoint client, byte[] data)
{
Client = client;
Data = data;
}
}
public class Server
{
private UdpClient listener;
/*
* you probably want to make this a bounded collection to prevent the
* collection from getting too big
*/
private BlockingCollection<Transmission> dataReceived = new BlockingCollection<Transmission>();
private bool receivePackets = true;
private bool processData = true;
private IPEndPoint groupEP;
public Server(IPEndPoint listenAt)
{
listener = new UdpClient(listenAt);
groupEP = listenAt;
}
public void Run()
{
ProcessData();
ReceiveData();
}
public async void ReceiveData()
{
await Task.Run(() => {
while (receivePackets)
{
byte[] data = listener.Receive(ref groupEP);
dataReceived.Add(new Transmission(groupEP, data));
}
});
}
public async void ProcessData()
{
//you could run just a few of these to increase your processing
//speed without changing how things work
await Task.Run(async () => {
while (processData)
{
//blocks until data is available
Transmission data = dataReceived.Take();
//do things with the data...
await Task.Delay(5000);
}
});
}
}
}
Как уже говорилось, в этом примере есть некоторые проблемы - если вы действительно хотите реализовать это, я настоятельно рекомендую сделать dataReceived
ограниченнымблокирует сбор, так что вам не нужно беспокоиться о проблемах с памятью.Кроме того, обычно полезно иметь возможность завершить весь процесс, передав CancellationToken на вызовы Take () и TryTake (), а также любые созданные вами потоки.Однако сам дизайн должен предусматривать простую многозадачность в случае, если обработка клиентов становится проблемой производительности.