启动许多异步操作可能会出现问题吗?
我正在编写TCP服务器,其中并发客户端的数量是上限。我想出了服务器包含一定数量的插槽的想法。每个插槽在共享BeginAcceptTcpClient
实例上启动异步TcpListener
调用。当客户端连接时,第一个可用的异步操作将通过回调返回。然后,我可以再次调用TcpClient
来处理BeginAcceptTcpClient
实例和可重新插入的插槽。使用这种架构,我不必手动关心同步计数器来限制客户端连接。 Incomming连接等待重新插入插槽。但我不确定这是不是一个好主意。
示例控制台程序:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace SlotTcpServerSample
{
internal class Program
{
private class Slot : IDisposable
{
private TcpListener _listener;
private EventWaitHandle _closed;
public Slot(TcpListener listener)
{
_listener = listener;
_closed = new ManualResetEvent(false);
}
public void Open(AsyncCallback callback)
{
_listener.BeginAcceptTcpClient(callback, this);
}
public void Close()
{
_closed.Set();
}
public void WaitForClose()
{
_closed.WaitOne();
}
public void Dispose()
{
_closed.Close();
}
}
private class TcpServer
{
private const int MAX = 10;
private object _sync;
private Slot[] _slots;
private IPEndPoint _endpoint;
private TcpListener _listener;
public TcpServer(IPEndPoint endpoint)
{
_sync = new object();
_endpoint = endpoint;
}
public void Start()
{
lock (_sync)
{
if (_listener != null)
return;
_listener = new TcpListener(_endpoint);
_slots = new Slot[MAX];
for (int i = 0; i < MAX; i++)
_slots[i] = new Slot(_listener);
_listener.Start();
foreach (Slot slot in _slots)
slot.Open(HandleConnection);
}
}
public void Stop()
{
lock (_sync)
{
if (_listener == null)
return;
_listener.Stop();
foreach (Slot slot in _slots)
{
slot.WaitForClose();
slot.Dispose();
}
_listener = null;
}
}
private void HandleConnection(IAsyncResult asyncResult)
{
Slot slot = (Slot)asyncResult.AsyncState;
TcpClient client = null;
try
{
client = _listener.EndAcceptTcpClient(asyncResult);
}
catch (ObjectDisposedException ex)
{
slot.Close();
return;
}
HandleClient(client);
try
{
slot.Open(HandleConnection);
}
catch (ObjectDisposedException ex)
{
slot.Close();
return;
}
}
private void HandleClient(TcpClient client)
{
Console.WriteLine("Connected: {0}", client.Client.RemoteEndPoint.ToString());
client.Close();
}
}
private static void Main(string[] args)
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 8080);
TcpServer server = new TcpServer(endpoint);
try
{
Console.WriteLine("Starting...");
server.Start();
Console.WriteLine("Started");
Console.ReadLine();
Console.WriteLine("Stopping...");
server.Stop();
Console.WriteLine("Stopped");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}