在这个问题之后,我决定从一个更具体的方法开始,而不是抛出我无法整合的理论和概念信息:Are Socket.*Async methods threaded?
重点是在优化服务器的同时保持所有客户端的流动性。这意味着以某种方式异步,以便不阻止主要操作。
以下是我提出的一些方法。 “过程”是一种处理从客户端接收的数据的假设方法。考虑到这通常需要1-5毫秒,对于罕见的数据库调用可能需要500-2000毫秒。
使用Socket。*异步和循环
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);
}
}
}
}
优点:
缺点:
我认为这是一个好的开始,也许是我最好的解决方案。如果我可以在一个线程池中混合,将accept,receive和process分成不同的线程,我们可能会去某个地方。
使用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);
}
}
优点:
缺点:
最后是一种简化此解决方案的方法,无需手动重置事件。
使用屏蔽调用和手动线程
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();
}
}
使用线程池
我实际上不知道如何使用它,有人可以给我一个例子吗?
建议
可能解决方案不是本文中的任何一个。你会怎么处理它?</ p>
正如你所看到的,我使用过。*异步方法,Begin * / End *方法和阻塞方法,但都有相对较大的缺点。
提前谢谢:)我迫不及待地想看看S / O的代码示例。
答案 0 :(得分:3)
您没有正确使用Begin/End
。没有必要等待事件,让框架处理这个。请注意,在the MSDN example中,接收循环不使用显式事件,尽管接受循环的作用是为了便于控制和说明。
static class Server
{
static Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
static void Main()
{
listener.Bind(new IPEndPoint(IPAddress.Any, 555));
listener.BeginAccept(OnAccept, null);
WaitUntilServerNeedsToShutdown () ;
// worker threads will die because they are background
}
private static void OnAccept(IAsyncResult ar)
{
new Receiver(listener.EndAccept(ar));
listener.BeginAccept(OnAccept, null);
}
}
class Receiver
{
Socket socket;
byte[] buffer = new byte[1024];
public Receiver(Socket socket)
{
this.socket = socket;
socket.BeginReceive(buffer, 0, 1024, SocketFlags.None, OnReceive, null);
}
private void OnReceive(IAsyncResult ar)
{
int received = socket.EndReceive(ar);
byte[] toProcess = new byte[received];
Buffer.BlockCopy(buffer, 0, toProcess, 0, received);
// TODO: detect EOF and error conditions
socket.BeginReceive(buffer, 0, 1024, SocketFlags.None, OnReceive, null);
// TODO: is it OK to process incomplete data?
Process(toProcess);
}
}