Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何以更好的方式创建异步TCP服务器?_C#_Sockets_Asynchronous_Async Await_Tcplistener - Fatal编程技术网

C# 如何以更好的方式创建异步TCP服务器?

C# 如何以更好的方式创建异步TCP服务器?,c#,sockets,asynchronous,async-await,tcplistener,C#,Sockets,Asynchronous,Async Await,Tcplistener,我有一个服务器应用程序,可以从大约10000个客户端(实际上是带有GPRS接口的现场设备)接受TCP连接 接受连接的部件如下所示: public async System.Threading.Tasks.Task AcceptConnections() { _listenerProxy.StartListen(); var taskList = new List<System.Threading.Tasks.Task>(); var application =

我有一个服务器应用程序,可以从大约10000个客户端(实际上是带有GPRS接口的现场设备)接受TCP连接

接受连接的部件如下所示:

public async System.Threading.Tasks.Task AcceptConnections()
{
    _listenerProxy.StartListen();
    var taskList = new List<System.Threading.Tasks.Task>();
    var application = _configManager.Configuration.GetSection("application");
    var maxTasks = int.Parse(application["MaxTasksPerListener"]);
    while (true)
    {
        if (taskList.Count > maxTasks)
        {
            _logger.Info($"Waiting for handling task to be completed {_listenerProxy.Port}.");
            await System.Threading.Tasks.Task.WhenAny(taskList.ToArray()).ConfigureAwait(false);
            taskList.RemoveAll(t => t.IsCompleted); // at least one task affected, but maybe more
        }
        _logger.Info($"Waiting for client to be accepted on port {_listenerProxy.Port}.");
        (var readStream, var writeStream, var sourceIP, var sourcePort) = await _listenerProxy.AcceptClient().ConfigureAwait(false);
        _logger.Info($"Client accepted on port {_listenerProxy.Port}: IP:{sourceIP}, Port:{sourcePort}");

        var clientContext = new ClientContext<TSendMessage, TReceiveMessage>
        {
            SourceAddress = sourceIP,
            SourcePort = sourcePort,
            DataAdapter = DataAdapterFactory<TSendMessage, TReceiveMessage>.Create(readStream, writeStream)
        };
        taskList.Add(HandleClient(clientContext));
    }
}
public async System.Threading.Tasks.Task AcceptConnections()
{
_listenerProxy.StartListen();
var taskList=新列表();
var application=_configManager.Configuration.GetSection(“应用程序”);
var maxstasks=int.Parse(应用程序[“maxstasksperlistener]”);
while(true)
{
如果(taskList.Count>maxTasks)
{
_Info($“正在等待处理任务完成{{u listenerProxy.Port}”);
wait System.Threading.Tasks.Task.WhenAny(taskList.ToArray()).configurewait(false);
taskList.RemoveAll(t=>t.IsCompleted);//至少有一个任务受到影响,但可能更多
}
_Info($“正在等待在端口{u listenerProxy.port}上接受客户端”);
(var readStream、var writeStream、var sourceIP、var sourcePort)=等待_listenerProxy.AcceptClient().ConfigureAwait(false);
_Info($“在端口{U listenerProxy.port}:IP:{sourceIP},端口:{sourcePort}上接受的客户端”);
var clientContext=新clientContext
{
SourceAddress=sourceIP,
SourcePort=SourcePort,
DataAdapter=DataAdapterFactory.Create(读流、写流)
};
添加(HandleClient(clientContext));
}
}
HandleClient方法定义为:

public async System.Threading.Tasks.Task HandleClient(ClientContext<TSendMessage, TReceiveMessage> clientContext);
public async System.Threading.Tasks.Task-HandleClient(ClientContext-ClientContext);
我希望能够并行处理多达预定义数量的请求(处理函数是
HandleClient
)。客户端将连接,发送少量数据,然后关闭连接。 因为整个项目都是异步的,所以我也尝试了异步方法

我确信这个解决方案是不被推荐的,但我不知道怎样才能做得更好。我在这里发现了一个非常密切相关的话题:

斯蒂芬·克利里在那里发表了评论:

嗯,我建议的第一件事是尝试一个简单的练习。 说真的,异步TCP服务器是最复杂的服务器之一 您可以选择的应用程序

那么,在这种情况下,“正确”的方法是什么?我知道,我的方法“有效”,但我有一种不好的感觉,尤其是
HandleClient
或多或少是“开火然后忘记”。我对结果任务感兴趣的唯一原因是“限制”吞吐量(最初它是异步的)。事实上,我的问题与链接中的TO完全相同。然而,我仍然不知道这种方法的最大问题是什么


我希望得到建设性的提示……谢谢。

一句话:红隼。抛开所有这些顾虑,同时获得许多其他好处,例如高级缓冲区生存期管理和面向异步的设计。这里的关键API是
UseConnectionHandler
,例如:

公共静态IWebHostBuilder CreateHostBuilder(字符串[]args)=>
WebHost.CreateDefaultBuilder(args).UseKestrel(选项=>
{//在端口1000上侦听,使用处理程序的YourHandlerHere
options.ListenLocalhost(1000,o=>o.UseConnectionHandler());
}).UseStartup();
您可以看到一个简单但可运行的示例(呵呵,如果您将一个功能主要与redis类似的服务器称为“普通”),或者我可能会向您提供私有github repos中的其他示例,包括一个示例,其中您所需做的就是实现帧解析器(库代码处理所有其他内容,并在TCP和UDP上工作)


至于“油门”——听起来像是一个异步信号灯
SemaphoreSlim
has
WaitAsync

将有助于改进工作代码。..TIL!“我不知道红隼能对付生的TCP。”斯蒂芬克利里:是的;而且,由于它将所有内容公开为“管道”(即,
PipeReader
PipeWriter
),因此您不需要处理任何后台缓冲区管理等,只需从入站获取您想要的内容即可pipe@Marc这就是我正在寻找的解决方案。但不幸的是,红隼是非常压倒性的,它听起来似乎需要几年才能适应它。您可以推荐从哪种文档开始?@MichaelW高容量套接字服务器从根本上说是复杂的-这是不可避免的。IMO Kestrel使它比我所知道的任何其他API都简单得多。也就是说,我确实在Pipelines.Sockets.non-official中有另一台服务器主机,它的工作原理类似,但没有Kestrel。我已经链接到一个工作服务器;我还可以在这里向您介绍我的三部分系列,其中涵盖了管道的大部分细节:,并讨论了非红隼host@Marc:根据您的示例,我将Kestrel集成为TCP套接字服务器。它起作用了。我使用基于管道的流,并且能够几乎原封不动地重用我的旧代码。我们已经将Kestrel用于其他方面(gRPC、度量等),但我不知道,我们也可以将其用于TCP套接字通信。谢谢!!!