- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
TCP 服务器是使用 SocketAsyncEventArgs 开发的,它是作为 Windows 服务的异步方法。我在 Main 的开头有这两行代码:
ThreadPool.SetMaxThreads(15000, 30000);
ThreadPool.SetMinThreads(10000, 20000);
并且都返回 true(记录返回值)。现在有 2000 到 3000 个客户端开始向该服务器发送消息,它开始接受连接(我计算了连接数,正如预期的那样——有一个连接池)。服务器进程的线程数将增长到 ~2050 到 ~3050。到目前为止一切顺利!
现在有一个 Received 方法,它将在 ReceiveAsync 返回 true 后或由 SocketAsyncEventArgs 的 Completed 事件调用。
问题从这里开始:无论有多少客户端连接以及它们发送了多少消息,Received 将在一秒钟内最多被调用 20 次!随着客户数量的增加,这个数字 (20) 下降到大约 10。
环境:在同一台机器上模拟 TCP 服务器和客户端。我在两台机器上测试了代码,一台有 2 核 CPU 和 4GB RAM,另一台有 8 核 CPU 和 12GB RAM。没有数据丢失(还),有时我在每次接收操作中收到超过 1 条消息。没关系。但是如何才能增加接收操作的数量呢?
关于实现的附加说明:代码很大,包含许多不同的逻辑。总体描述是:我有一个 SocketAsyncEventArgs 用于接受新连接。它很好用。现在,对于每个新接受的连接,我创建一个新的 SocketAsyncEventArgs 来接收数据。我将这个(为接收创建的 SocketAsyncEventArgs)放在池中。它不会被重用,但它的 UserToken 被用于跟踪连接;例如,那些断开连接或 7 分钟内未发送任何数据的连接将被关闭和处置(SocketAsyncEventArgs 的 AcceptSocket 将被关闭(两者)、关闭和处置,SocketAsyncEventArgs 对象本身也是如此)。这是一个执行这些任务的 Sudo 类,但删除了所有其他逻辑、日志记录和错误检查以及任何其他内容以使其简单明了(也许这样更容易发现有问题的代码):
class Sudo
{
Socket _listener;
int _port = 8797;
public Sudo()
{
var ipEndPoint = new IPEndPoint(IPAddress.Any, _port);
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listener.Bind(ipEndPoint);
_listener.Listen(100);
Accept(null);
}
void Accept(SocketAsyncEventArgs acceptEventArg)
{
if (acceptEventArg == null)
{
acceptEventArg = new SocketAsyncEventArgs();
acceptEventArg.Completed += AcceptCompleted;
}
else acceptEventArg.AcceptSocket = null;
bool willRaiseEvent = _listener.AcceptAsync(acceptEventArg); ;
if (!willRaiseEvent) Accepted(acceptEventArg);
}
void AcceptCompleted(object sender, SocketAsyncEventArgs e)
{
Accepted(e);
}
void Accepted(SocketAsyncEventArgs e)
{
var acceptSocket = e.AcceptSocket;
var readEventArgs = CreateArg(acceptSocket);
var willRaiseEvent = acceptSocket.ReceiveAsync(readEventArgs);
Accept(e);
if (!willRaiseEvent) Received(readEventArgs);
}
SocketAsyncEventArgs CreateArg(Socket acceptSocket)
{
var arg = new SocketAsyncEventArgs();
arg.Completed += IOCompleted;
var buffer = new byte[64 * 1024];
arg.SetBuffer(buffer, 0, buffer.Length);
arg.AcceptSocket = acceptSocket;
arg.SocketFlags = SocketFlags.None;
return arg;
}
void IOCompleted(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
Received(e);
break;
default: break;
}
}
void Received(SocketAsyncEventArgs e)
{
if (e.SocketError != SocketError.Success || e.BytesTransferred == 0 || e.Buffer == null || e.Buffer.Length == 0)
{
// Kill(e);
return;
}
var bytesList = new List<byte>();
for (var i = 0; i < e.BytesTransferred; i++) bytesList.Add(e.Buffer[i]);
var bytes = bytesList.ToArray();
Process(bytes);
ReceiveRest(e);
Perf.IncOp();
}
void ReceiveRest(SocketAsyncEventArgs e)
{
e.SocketFlags = SocketFlags.None;
for (int i = 0; i < e.Buffer.Length; i++) e.Buffer[i] = 0;
e.SetBuffer(0, e.Buffer.Length);
var willRaiseEvent = e.AcceptSocket.ReceiveAsync(e);
if (!willRaiseEvent) Received(e);
}
void Process(byte[] bytes) { }
}
最佳答案
它变慢的原因是因为这些线程中的每一个都需要上下文切换,而这是一个相对昂贵的操作。您添加的线程越多,您的 CPU 的百分比就越大,只是花在上下文切换上,而不是花在实际代码上。
您以一种相当奇怪的方式遇到了每个客户端一个线程的瓶颈。服务器端异步的全部意义在于减少线程数量——每个客户端没有一个线程,但理想情况下系统中的每个逻辑处理器只有一个或两个线程。 p>
您发布的异步代码看起来不错,所以我只能猜测您的 Process
方法中有一些容易被忽略的非异步、阻塞 I/O,即数据库或文件访问。当 I/O 阻塞时,.NET 线程池会检测到这一点并自动启动一个新线程——它基本上在这里失去控制,Process
中的 I/O 成为瓶颈。
异步管道确实需要 100% 异步才能从中获得任何显着优势。 Half-in 会让您编写复杂的代码,其性能与简单的同步代码一样差。
如果您绝对不能使 Process
方法完全异步,您可能会伪装它。让事情在队列中等待,以供小型、有限大小的线程池处理。
关于c# - 使用 SocketAsyncEventArgs 每秒接收 20 次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14044852/
我有时会收到此错误: An asynchronous socket operation is already in progress using this SocketAsyncEventArgs i
我试图理解 C# 中的“SocketAsyncEventArgs”类。 http://msdn.microsoft.com/en-us/library/system.net.sockets.socke
我的 SocketAsyncEventArgs 类有问题..问题是当我尝试发送 8K 数据时例如在互联网上,套接字有时只发送 1K 或 2K,我知道这是正常的TCP 套接字和一次发送并不能保证一次接收
我正在为我的分布式系统编写消息层。我正在使用 IOCP,即 Socket.XXXAsync 方法。 下面是一些与我正在做的非常接近的东西(事实上,我的接收函数是基于他的): http://vadmys
在我的场景中,有许多客户端的 tcp 套接字连接到服务器。服务器从所有套接字接收 ReceiveAsync(),当回调被无误调用时,解析接收到的数据。如果一个套接字接收到的数据是某种类型的消息,则接收
我在 SocketAsyncEventArgs buffer is full of zeroes 中描述了类似的问题其中我的 SocketAsyncEventArgs UDP 服务器的实现接收具有以下
似乎无法在 .NET Socket 类的 AcceptAsync() 方法上指定超时。它接受一个 SocketAsyncEventArgs if (!socket.AcceptAsync(awaita
我最初在发送数据时遇到了竞争条件,问题是我允许使用多个 SocketAsyncEventArgs 来发送数据,但是第一个数据包在第二个数据包之前没有完全发送,这是因为我有它如果数据不适合缓冲区,它会循
我正在使用 SocketAsyncEventArgs 与数百种设备进行通信(其中大部分通过 GPRS)。有时,它们中的一些会停止响应,而且我似乎无法使操作超时,因为文档指出超时选项(即 SocketO
是否有正当理由不使用 TcpListener 而不是 SocketAsyncEventArgs 来实现高性能/高吞吐量 TCP 服务器? 我已经使用 SocketAsyncEventArgs 实现了这
好吧,我读了很多关于编写高可扩展服务器的问题,但我从来没有真正找到一个好的答案。无论如何,我想创建一个可扩展的客户端,它可以处理大量数据和连接。我创建的是一个使用 SocketAsyncEventAr
我四处寻找,很惊讶地发现绝对没有可以回答这个问题: 如何在使用 SocketAsyncEventArgs 时实现 SSL/TLS(或类似)加密?我确实读过,理论上可以使用SslStream 和“作弊”
所以我已经用 SocketAsyncEventArgs 和 socket.***Async 方法编写了一个 tcp 服务器。但我确实喜欢使用 Stream.ReadAsync 和 Stream.Wri
当使用“SocketAsyncEventArgs”类和 ReadAsync 时,我应该将读取缓冲区放在哪里以及将发送缓冲区放在哪里?或者我只能一次阅读或发送而不是两者?我有点困惑。 最佳答案 我认为您
我想使用 SocketAsyncEventArgs 事件创建一个异步套接字服务器。 服务器应该同时管理大约 1000 个连接。处理每个数据包逻辑的最佳方式是什么? 服务器设计基于this MSDN e
我一直在使用.NET 3.5异步套接字API,发现所有* Async方法都返回一个 bool 值,如果该操作同步完成,则它为false。 我对如何/为什么会发生这种情况感到困惑。这并不总是错误的情况,
我正在测试以下两种情况,一种有效,但另一种无效。我有套接字服务器和套接字客户端应用程序在两台不同的机器上运行 这两个场景都使用了 socketasynceventargs 场景 1(有效)循环创建 4
我有一个使用 SocketAsyncEventArgs 异步接收 UDP 数据包的标准实现。我从文档和一些谷歌搜索中不明白的是,我是否应该在回调本身内部完成处理消息的实际工作,比如 this comm
我正致力于使用 IOCP 和 SocketAsyncEventArgs 实现高性能服务器。据我所知,使用这种方法获取 SSL 并不“容易”,因为我发现您要么需要自己实现 SSL,要么以某种方式将使用
我看不到 pooled SocketAsyncEventArgs样式帮助我减少了为许多并发连接提供服务的服务器的内存消耗。 是的,它提供了 MS 的 Begin/End 样式的替代方案,上述 MSDN
我是一名优秀的程序员,十分优秀!