C# .NET 服务器轮询多个连接 - 有更好的方法吗?

标签 c# asynchronous tcp polling

我正在使用 .NET C# 开发 TCP 服务器。它使用异步 I/O(I/O 完成)来同时处理大量客户端。现在,我将所有 TCP 连接都列在一个列表中,我不断地通过它来寻找任何特定连接的状态机的变化。一旦 I/O 完成设置了某些标志,给定连接的状态机就会更新。

我确信有更好的方法来做到这一点——当前的实现是非常处理器密集型的,因为我没有阻塞等待更新,而是在没有节流的情况下进行轮询。我真的不在乎我的服务器是否在浪费周期,但我猜这是糟糕的设计。我试图找到一种方法来处理特定的连接,只有当 I/O 完成信号有东西要处理时才处理,而在没有时等待(即 sleep )。任何人都可以建议一个好的方法吗?

我在想一些线程同步的事情可能会在循环的主线程等待任何 I/O 完成释放它的情况下工作。但是,有时会使用调用线程执行 I/O 完成(当数据立即可用时等),因此这会导致此解决方案出现问题。

如有任何建议,我们将不胜感激!

这是由主线程执行的(简化的)循环(rgClient 是客户端列表):

//Do communications on each client we currently have connected.
//This loops runs backwards so we can delete elements on the fly
//without have to iterate through more than once.
lock (rgClient)
{
    for (i = rgClient.Count - 1; i >= 0; i--)
    {
        if (!rgClient[i].DoComm())
        {
            rgClient[i].DoClose();
            rgClient.RemoveAt(i);
        }
    }
}

DoComm() 对连接的状态机执行更新,这涉及执行当前状态的事件,然后在必要时转换到新状态。这是发送简单“ack”数据包的状态类:

class StateAck : State
{
    public StateAck(TextBox txtOutputExt, Form fmOwner)
        : base(txtOutputExt, fmOwner)
    {
        fWriting = false;
    }

    public override bool DoExecute(out Type tpNextState)
    {
        PktAck pkt;

        if (!base.DoExecute(out tpNextState))
        {
            return false;
        }

        //Start a write if we haven't yet
        if (!fWriting)
        {
            pkt = new PktAck();
            fWriting = true;

            return FPutPkt(pkt.rgbSerialize());
        }

        //Is the read finished / has an error occurred?
        if (fDataErrorWrite)
        {
            return false;
        }

        //Process the data
        if (fDataWritten)
        {
            tpNextState = typeof(StateIdle);
        }

        return true;
    }

    private bool fWriting;
}

每次从主线程调用 DoComm() 时,都会通过 DoExecute() 执行。 99% 的时间,实际上什么都没有发生。当写入(通过调用 FPutPkt() 启动)完成时,一个标志将发出信号,然后下一个状态设置为“空闲”。我想做的是让主线程只检查已完成网络事件并需要更新某些内容的客户端,以避免通过 DoExecute() 进行持续和冗余的传递。

最佳答案

我找到了一个似乎非常有效的解决方案。使用 EventWaitHandler (System.Threading),在每次通过循环的底部自动重置为 WaitOne()。然后任何回调或辅助线程都可以通过调用 EWH.Set() 向 EventWaitHandler 发出信号,这将允许循环进行另一次传递。在不对程序流程进行重大修改的情况下消除轮询循环的 CPU 使用率的好方法。希望对某人有所帮助。

关于C# .NET 服务器轮询多个连接 - 有更好的方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4235077/

相关文章:

ruby - 我可以使用 Ruby 通过 TCP 发送对象吗?

c# - Unity3D C#。使用 transform.RotateAround() 函数同时保持两个对象之间的距离不变

c# - 将对象转换到实际类

c# - Xamarin listView 中的绑定(bind)颜色

c# - 在 EF Core 3.1 中加入群组

sockets - 可以创建多少个 tcp 连接

Javascript,addEventListener 回调函数立即执行并且只执行一次?

javascript - jQuery 延迟 : use to delay return of function until async call within function complete + get return value

asynchronous - F# Async.FromBeginEnd 不捕获异常

c# - 在 c# 中作为 Windows 服务运行时,TCP/IP 套接字不从机器读取数据