gpt4 book ai didi

c# - 哪种线程方法最适合主服务器网络?

转载 作者:行者123 更新时间:2023-12-03 11:58:36 29 4
gpt4 key购买 nike

提出了这个问题之后,我决定从一种更具体的方法开始,而不是抛出我无法整合的理论和概念信息: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);
}
}
}
}

优点:
  • 仅一个线程!
  • 相当容易管理。

  • 缺点:
  • While(true):是否过于占用CPU?
  • 由于所有操作都互相关注,因此它们降低了所有连接的客户端的速度。

  • 我认为这是一个好的开始,也许是我最好的解决方案。如果我可以混入一个线程池中,将接受,接收和进程分成不同的线程,我们可能会去某个地方。

    使用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();
    }
    }

    使用线程池

    我实际上不知道如何使用它,有人可以给我一个例子吗?

    建议

    解决方案可能不是本文中的任何解决方案。您将如何处理?

    如您所见,我使用了。* Async方法,Begin */End *方法和阻塞方法,但是它们都有相对较大的缺点。

    在此先感谢:)我迫不及待地想看到S/O的代码示例。

    最佳答案

    您没有正确使用Begin/End。无需等待事件,让框架来处理。请注意,在the MSDN example中,receive循环不使用显式事件,尽管accept循环用于简化控制和展示。

    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);
    }
    }

    关于c# - 哪种线程方法最适合主服务器网络?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5363563/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com