gpt4 book ai didi

c# - 如何使用 C# 4.0 编写可扩展的套接字服务器?

转载 作者:太空狗 更新时间:2023-10-29 18:16:44 27 4
gpt4 key购买 nike

我想编写一个简单的套接字服务器,但我希望它可以垂直扩展,例如,不为每个连接创建一个线程或运行很长时间的任务,这可能会消耗所有线程。

服务器接收到包含查询的请求并传输任意大的结果。

我希望使用 C# 4 中可用的技术和库以惯用的方式来执行此操作,并强调简单的代码,而不是原始性能。

重新开放套接字服务器是可扩展系统的有用部分。如果你想水平扩展,有不同的技术。如果您从未创建过套接字服务器,您可能无法回答这个问题。

最佳答案

我已经在做类似的事情一两周了,所以希望我能帮到你一点。

如果您关注的是简单的代码,我建议您使用 TcpClient 和 TcpListener 类。它们都使套接字更易于使用。虽然它们自 .NET Framework 1.1 以来就已经存在,但它们已经过更新并且仍然是您的最佳选择。

关于如何利用.NET Framework 4.0 编写简单的代码,首先想到的是Tasks。它们使编写异步代码变得不那么痛苦,并且一旦 C# 5 发布 (new async and await keywords),迁移您的代码将变得更加容易。以下是 Tasks 如何简化代码的示例:

而不是使用 tcpListener.BeginAcceptTcpClient(AsyncCallback callback, object state); 并提供一个回调方法来调用 EndAcceptTcpClient(); 并选择性地转换你的状态对象, C# 4 允许您利用闭包、lambda 和任务来使该过程更具可读性和可扩展性。这是一个例子:

private void AcceptClient(TcpListener tcpListener)
{
Task<TcpClient> acceptTcpClientTask = Task.Factory.FromAsync<TcpClient>(tcpListener.BeginAcceptTcpClient, tcpListener.EndAcceptTcpClient, tcpListener);

// This allows us to accept another connection without a loop.
// Because we are within the ThreadPool, this does not cause a stack overflow.
acceptTcpClientTask.ContinueWith(task => { OnAcceptConnection(task.Result); AcceptClient(tcpListener); }, TaskContinuationOptions.OnlyOnRanToCompletion);
}

private void OnAcceptConnection(TcpClient tcpClient)
{
string authority = tcpClient.Client.RemoteEndPoint.ToString(); // Format is: IP:PORT

// Start a new Task to handle client-server communication
}

FromAsync非常有用,因为 Microsoft 提供了许多可以简化常见异步操作的重载。这是另一个例子:

private void Read(State state)
{
// The int return value is the amount of bytes read accessible through the Task's Result property.
Task<int> readTask = Task<int>.Factory.FromAsync(state.NetworkStream.BeginRead, state.NetworkStream.EndRead, state.Data, state.BytesRead, state.Data.Length - state.BytesRead, state, TaskCreationOptions.AttachedToParent);

readTask.ContinueWith(ReadPacket, TaskContinuationOptions.OnlyOnRanToCompletion);
readTask.ContinueWith(ReadPacketError, TaskContinuationOptions.OnlyOnFaulted);
}

State 只是一个用户定义的类,通常只包含 TcpClient 实例、数据(字节数组),也许还包含读取的字节。

如您所见,ContinueWith 可用于替换许多繁琐的 try-catches,直到现在这些操作都是必不可少的。

在帖子的开头,您提到不想为每个连接创建一个线程或创建运行时间很长的任务,我想我现在应该解决这个问题。就个人而言,我没有看到为每个连接创建线程的问题。

然而,您必须小心的是,将任务(ThreadPool 的抽象)用于长时间运行的操作。 ThreadPool 很有用,因为创建新线程的开销不可忽略,对于读取或写入数据和处理客户端连接等短任务,首选任务。

您必须记住,ThreadPool 是具有专门功能的共享资源(避免花费更多时间创建线程而不是实际使用它的开销)。因为它是共享的,所以如果您使用一个线程,另一个资源就不能,这会很快导致线程池不足和 deadlock场景。

关于c# - 如何使用 C# 4.0 编写可扩展的套接字服务器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7654632/

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