Следуя этому вопросу, я решил начать с более конкретного подхода, вместо того, чтобы бросать теоретическую и концептуальную информацию, которую я не могу интегрировать: Являются ли Socket. * Асинхронные методы в потоке?
Суть в том, чтобы сохранить текучесть для всех клиентов при оптимизации сервера. Это означает асинхронность тем или иным способом, чтобы не блокировать основную операцию.
Вот некоторые методы, которые я придумал. «Процесс» - это гипотетический метод, который обрабатывает данные, полученные от клиента. Учтите, что обычно это может занять 1-5 мс, возможно, 500-2000 мс для редких вызовов базы данных.
Использование сокета. * Асинхронизация и цикл
static void Main()
{
Socket listener = new Socket(...);
listener.Bind(new IPEndPoint(IPAddress.Any, 555));
List<Socket> clients = new List<Socket>();
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
while (true)
{
if (listener.AcceptAsync(e))
{
clients.Add(e.AcceptSocket);
}
foreach (Socket client in clients)
{
if (client.ReceiveAsync(e))
{
Process(e.Buffer);
}
}
}
}
Плюсы:
- Только одна тема!
- Довольно прост в управлении.
Минусы:
- Хотя (верно): слишком высокая загрузка ЦП?
- Поскольку все операции следуют друг за другом, они замедляют работу всех подключенных клиентов.
Полагаю, это как-то хорошее начало, возможно, лучшее из моих решений. Если бы я мог смешать в пуле потоков, разделить принятие, получение и процесс в разных потоках, мы могли бы куда-то идти.
Использование Socket.Begin * / End * и ManualResetEvent
static class Server
{
static Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
static ManualResetEvent acceptDone = new ManualResetEvent(false);
static void Main()
{
listener.Bind(new IPEndPoint(IPAddress.Any, 555));
while (true)
{
acceptDone.Reset();
listener.BeginAccept(OnAccept, null);
acceptDone.WaitOne();
}
}
private static void OnAccept(IAsyncResult ar)
{
acceptDone.Set();
new Receiver(listener.EndAccept(ar));
}
}
class Receiver
{
Socket socket;
byte[] buffer = new byte[1024];
static ManualResetEvent receiveDone = new ManualResetEvent(false);
public Receiver(Socket socket)
{
this.socket = socket;
new Thread
(
delegate()
{
while (true)
{
receiveDone.Reset();
socket.BeginReceive(buffer, 0, 1024, SocketFlags.None, OnReceive, null);
receiveDone.WaitOne();
}
}
).Start();
}
private void OnReceive(IAsyncResult ar)
{
receiveDone.Set();
int received = socket.EndReceive(ar);
byte[] toProcess = new byte[received];
Buffer.BlockCopy(buffer, 0, toProcess, 0, received);
Process(toProcess);
}
}
Плюсы:
- Полностью асинхронный, клиенты никогда не тормозятся другими операциями.
- Использование ManualResetEvents позволяет красиво остановить сервер.
Минусы:
- Слишком много потоков, по 1 на клиента!
- Потерянное время обработки, поскольку все потоки заблокированы событиями сброса?
И, наконец, способ упростить это решение без ручного сброса событий.
Использование блокирующих вызовов и ручных потоков
static class Server
{
static Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
static void Main()
{
listener.Bind(new IPEndPoint(IPAddress.Any, 555));
while (true)
{
new Receiver(listener.Accept());
}
}
}
class Receiver
{
Socket socket;
public Receiver(Socket socket)
{
this.socket = socket;
new Thread
(
delegate()
{
while (true)
{
byte[] buffer = new byte[1024];
int received = socket.Receive(buffer);
byte[] toProcess = new byte[received];
Buffer.BlockCopy(buffer, 0, toProcess, 0, received);
Process(toProcess);
}
}
).Start();
}
}
Использование пула потоков
На самом деле я понятия не имею, как его использовать, может кто-нибудь дать мне пример для этого?
Предложения
Вероятно, решение не из тех, что приведены в этом посте. Как бы вы справились с этим?
Как видите, я использовал. * Асинхронные методы, методы Begin * / End * и методы блокировки, но все они имеют относительно серьезные недостатки.
Заранее спасибо :) Не могу дождаться, чтобы увидеть примеры кода S / O.